EF 4.1 Mapping Problem
I have a class that have a relationship with itself:
public class Person
{
public long ID { get; set; }
public string Name { get; set; }
public virtual Person Mother { get; set; }
public virtual Person Father { get; set; }
}
When EF 4.1 is trying to map this class I'm ge开发者_如何学Ctting the follow error: 'Unable to determine the principal end of an association between the types 'Model.Person' and 'Model.person'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.'
I already tried the solution of the topic EF 4.1 - Model Relationships without success.
How I can fix that?
Thanks!
Because it's naturally a one-to-many relationship (a person must have one father and one mother but can have many sons and daughters) I'd model it like this:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasRequired(p => p.Father)
.WithMany();
modelBuilder.Entity<Person>()
.HasRequired(p => p.Mother)
.WithMany();
}
This will create two required foreign keys in the database table with name Mother_ID
and Father_ID
by convention.
Edit
If you want to be able to create persons without Mother and Father you can make the relation optional instead of required:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOptional(p => p.Father)
.WithMany();
modelBuilder.Entity<Person>()
.HasOptional(p => p.Mother)
.WithMany();
}
Then the foreign keys in the database table are nullable.
If you don't like the default column names for your foreign keys (Mother_ID
and Father_ID
) you can customize the column names in your mapping:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Person>()
.HasOptional(p => p.Father)
.WithMany()
.Map(m => m.MapKey("FatherID"));
modelBuilder.Entity<Person>()
.HasOptional(p => p.Mother)
.WithMany()
.Map(m => m.MapKey("MotherID"));
}
For anyone else wondering, this apparently can't be done via DataAnnotation attributes, but can only be configured fluently. http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/08bba96a-20b2-4a3c-9e0e-a5475b703dfe
It's a tad weird but you can do this without the modelBuilder gunk like so:
public class RecursiveModel
{
public long Id { get; set; }
public string Name { get; set; }
public RecursiveModel Father { get; set; }
public RecursiveModel Mother { get; set; }
public ICollection<RecursiveModel> Children { get; set; }
}
So basically one of these models will have a list of its children, and if for example this is a mother, each of them will have both their Mother_Id and RecursiveModel_Id set to this object. You'll need to explictly wire it up each time, ideally via a helper method like:
public void AddAsMotherOfChild(RecursiveModel child)
{
Children.Add(child);
child.Mother = this;
}
public void AddAsFatherOfChild(RecursiveModel child)
{
Children.Add(child);
child.Father = this;
}
Not perfect but it does avoid the modelBuilder code that for me at least gets to be sort of brittle and legion over time.
精彩评论