I’m trying to make a one to many self reference using EF4.1 code first. My entity looks like this
public class Site
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Sitename { get; set; }
public virtual Site ChildSite { get; set; }
public virtual ICollection<Site> ChildSites { get; set; }
}
And in my context class I do this to make the self reference
modelBuilder.Entity<Site>()
.HasOptional(s => s.ChildSite)
.WithMany(s => s.ChildSites)
.HasForeignKey(s => s.ParentId);
But when i try to add some dummy data to my database with this code
var sites = new List<Site>
{
new Site { ParentId = 0, Sitename = "Top 1" },
new Site { ParentId = 0, Sitename = "Top 2" },
new Site { ParentId = 0, Sitename = "Top 3" },
new Site { ParentId = 0, Sitename = "Top 4" },
new Site { ParentId = 1, Sitename = "Sub 1_5" },
new Site { ParentId = 1, Sitename = "Sub 1_6" },
new Site { ParentId = 1, Sitename = "Sub 1_7" },
new Site { ParentId = 1, Sitename = "Sub 1_8" },
new Site { ParentId = 2, Sitename = "Sub 2_9" },
new Site { ParentId = 2, Sitename = "Sub 2_10" },
new Site { ParentId = 2, Sitename = "Sub 2_11" },
new Site { ParentId = 2, Sitename = "Sub 2_12" },
new Site { ParentId = 3, Sitename = "Sub 3_13" },
new Site { ParentId = 3, Sitename = "Sub 3_14" },
new Site { ParentId = 3, Sitename = "Sub 3_15" },
new Site { ParentId = 3, Sitename = "Sub 3_16" },
new Site { ParentId = 4, Sitename = "Sub 4_17" },
new Site { ParentId = 4, Sitename = "Sub 4_18" },
new Site { ParentId = 4, Sitename = "Sub 4_19" },
new Site { ParentId = 4, Sitename = "Sub 4_20" }
};
sites.ForEach(s => context.Sites.Add(s));
context.SaveChanges();
I get this error :
Unable to determine the principal end of the
‘Cms.Model.Site_ChildSite’ relationship. Multiple added entities may
have the same primary key.
What am i missing here ?
Edit :
Here is the solution to my problem. I removed the public virtual Site ChildSite { get; set; } from the entity
public class Site
{
public int Id { get; set; }
public int? ParentId { get; set; }
public string Sitename { get; set; }
public virtual ICollection<Site> ChildSites { get; set; }
}
I then changed the modelBuilder to this
modelBuilder.Entity<Site>()
.HasMany(s => s.ChildSites)
.WithOptional()
.HasForeignKey(s => s.ParentId);
As it seems that auto generation of the database did not work I went ahead and created the table myself like this
int Id, not null, primary key
int ParentId, null
string Sitename, null
And everything works as I want it to.
2nd Edit
And the final step to get the auto generation of dummy data to work
var parent1 = new Site
{
Sitename = "Top 1",
ChildSites = new List<Site>
{
new Site {Sitename = "Sub 1_5"},
new Site {Sitename = "Sub 1_6"},
new Site {Sitename = "Sub 1_7"},
new Site {Sitename = "Sub 1_8"}
}
};
ect . . .
context.Sites.Add(parent1);
context.SaveChanges();
See Slauma answer below
Your mapping is correct and you don’t need to remove the
ChildSiteproperty. You just can’t use foreign key properties when you create your entities and “guess” how those autogenerated numbers will be after the entities are stored and use these numbers in the same entities which are being stored.The following instead should work and create the expected rows in the database:
Edit
If the entities represented by a foreign key exists in the DB you can use it – for example:
Add a new child:
Remove a child:
etc.