Mark Sizer
Mark Sizer

Reputation: 153

Entity Framework code-first, one-to-zero-to-one and one-to-many relationship to same entity

I'm creating a code-first database with v6.0 of the Entity Framework. I have an Organisation class and a related Location class defined in c# as follows:

public class Organisation
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Location> Locations { get; set; }

    public int? HQLocationId { get; set; }
    public Location HQLocation { get; set; }
}

public class Location
{
    public int Id { get; set; }
    public string Name { get; set; }

    public int OrganisationId { get; set; }
    public Organisation Organisation { get; set; }
}

As can be inferred from the classes, an Organisation can have multiple Locations, however it can only have one Head Quarters Location.

I'm using the Fluent API to configure the relationships between these classes. The "multiple locations" aspect is simple enough and works with the following:

   HasMany(o => o.Locations)
      .WithRequired(o => o.Organisation)   
      .HasForeignKey(l => l.OrganisationId);

I cannot however seem to find the correct syntax to define the relationship that allows the HQ location to be defined. If there a flaw in the approach I'm taking, or am I simply missing the right syntax?

UPDATE

If I add the following to the Organisation configuration:

   HasOptional(o => o.HQLocation)
      .WithMany()
      .HasForeignKey(o => o.HQLocationId)
      .WillCascadeOnDelete(true);

Then Entity Framework no longer errors and my data loads in a shape that suits my needs.

However this allows a Location to be the HQ for more than one Organisation; which ideally I do not want possible.

Upvotes: 1

Views: 1089

Answers (1)

Adil Mammadov
Adil Mammadov

Reputation: 8706

In one-to-one or one-to-zero or one relationships Id should be same on both entities. This means that Organisation.Id must be same as Location.Id for HQLocation. And of course, it is not good design choice. What I recommend is to add property to Location to indicate whether it is a HQLocation or not:

public class Organisation
{
    public int Id { get; set; }
    public string Name { get; set; }

    public virtual ICollection<Location> Locations { get; set; }
}

public class Location
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsHqLocation { get; set; }

    public int OrganisationId { get; set; }
    public Organisation Organisation { get; set; }
}

Upvotes: 1

Related Questions