JD41 February 2016

Entity Framework Code First - strange behaviour with circular relationship

I'm struggling to understand how Code First sets up relationships based on the model. Here's the model:

public class Person
{
    [Key]
    public string PersonName { get; set; }

    [Required]
    public virtual Nation NationOfBirth { get; set; }

    [Required]
    public virtual Nation CurrentNationOfResidence { get; set; }
}

public class Nation
{
    [Key]
    public string NationName { get; set; }

    public virtual Person CurrentSecondInCommand { get; set; }
}

At first I got an error while creating the database, which I was able to solve by adding a couple of modelBuilder commands:

modelBuilder.Entity<Person>()
    .HasRequired(p => p.NationOfBirth)
    .WithRequiredDependent()
    .WillCascadeOnDelete(false);
modelBuilder.Entity<Person>()
    .HasRequired(p => p.CurrentNationOfResidence)
    .WithRequiredDependent()
    .WillCascadeOnDelete(false);

And I also added:

modelBuilder.Entity<Nation>()
    .HasOptional(n => n.CurrentSecondInCommand)
    .WithOptionalDependent()
    .WillCascadeOnDelete(false);

Now when I try and populate my database, with the following code:

var america = new Nation { NationName = "America" };
context.Nations.Add(america);
var bush = new Person { PersonName = "Bush", CurrentNationOfResidence = america, NationOfBirth = america };
var obama = new Person { PersonName = "Obama", CurrentNationOfResidence = america, NationOfBirth = america };
var biden = new Person { PersonName = "Biden", CurrentNationOfResidence = america, NationOfBirth = america };
context.People.Add(bush);
context.People.Add(obama);
context.People.Add(biden);
context.SaveChanges();

At the point at which 'bush' is added, both the CurrentNationOfResidence and the NationOfBirth properties are not null for him and are set to be the 'america' object. But as soon as 'obama' is added, the CurrentNationOfReside

Answers


Ivelin Ivanov February 2016

The virtual property in Nation class must be ICollection<Person> CurrentSecondInCommand, that way you will have "many persons in one nation" in the database the relationship will be "one to many" not "one to one"


tede24 February 2016

The two relations from Person to Nation aren't one to one, but many to one:

  • A Person must have a single (Nation) NationOfBirth. BUT a Nation has many persons born there
  • A Person must have a single (Nation) CurrentNationOfResidence. BUT a Nation has many residents

So your configuration should be:

modelBuilder.Entity<Person>()
    .HasRequired(p => p.NationOfBirth)
    .WithMany()
    .WillCascadeOnDelete(false);
modelBuilder.Entity<Person>()
    .HasRequired(p => p.CurrentNationOfResidence)
    .WithMany()
    .WillCascadeOnDelete(false);

Post Status

Asked in February 2016
Viewed 2,861 times
Voted 4
Answered 2 times

Search




Leave an answer