2015-04-16 51 views
2

我试图在EF6中为以下自引用人类建模。如何使用实体框架正确建模自引用多父项关系

public class Person 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 

    public int? MotherId { get; set; } 
    public Person Mother { get; set; } 

    public int? FatherId { get; set; } 
    public Person Father { get; set; } 

    public virtual ICollection<Person> Children { get; set; } 
} 

而且我的DbContext是这样的:

public virtual DbSet<Person> People { get; set; } 

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Entity<Person>() 
     .HasOptional(m => m.Mother) 
     .WithMany(c => c.Children) 
     .HasForeignKey(m => m.MotherId); 

    modelBuilder.Entity<Person>() 
     .HasOptional(f => f.Father) 
     .WithMany(c => c.Children) 
     .HasForeignKey(f => f.FatherId); 
} 

当尝试使用下面的代码的人添加到数据库:

db.People.Add(new Person { Name = "Jane Doe" }); 

我得到这个错误:

An unhandled exception of type 'System.InvalidOperationException' occurred in EntityFramework.dll

Additional information: Sequence contains no matching element

这个错误是什么意思,我该如何纠正?另外,有没有更好的方法来建模这个对象(例如:使用母亲的子类:人和父:人)?

回答

1

我想出了以下的解决方案,产生一个干净的数据库,并允许更大的灵活性,将关系时:

public interface IParent 
{ 
    ICollection<Person> Children { get; set; } 
} 

public class Person 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 

    public int? MotherId { get; set; } 
    public Female Mother { get; set; } 

    public int? FatherId { get; set; } 
    public Male Father { get; set; } 
} 

public class Male : Person, IParent 
{ 
    public virtual ICollection<Person> Children { get; set; } 
} 

public class Female : Person, IParent 
{ 
    public virtual ICollection<Person> Children { get; set; } 
} 

的的DbContext只包含:

public virtual DbSet<Person> People { get; set; } 
public virtual DbSet<Female> Females { get; set; } 
public virtual DbSet<Male> Males { get; set; } 

而生成的数据库是这样的:

ID Name MotherId FatherId Discriminator 
1 Jane NULL  NULL  Female 
2 John NULL  NULL  Male 
3 Jimmy 1   2   Male 
4 Jenn 1   2   Female 

该解决方案还提供了将在多个方面关系的灵活性:

mom.Children.Add(son); // or 
son.Mother = mom; 
+0

你如何指定FK? – Ewan

+1

您不需要 - 默认情况下,EF使用相关实体的PK,按照惯例,这是名为ID或ClassNameID的道具。 –

0

我会做以下事情。虽然它可能不适合你“在实体框架的要求

public class Person 
{ 
    public int ID { get; set; } 
    public string Name { get; set; } 

    public int? MotherId { get; set; } 
    public int? FatherId { get; set; } 
} 

public Class RelationFinder 
{ 
    Public Person GetMother(IEnumerable<Person> people, Person child) 
    { 
     return people.FirstOrDefault(p=>p.Id = child.MotherId); 
    } 

    Public Person GetFather(... 

    Public IEnumerable GetChildern(... 
} 
+0

这是一个不错的选择,但我想坚持EF内置的魔术,写少的额外代码尽可能。 –

+0

不幸的是,EFs magic dosnt可以与可空的FKs和自引用结合使用。也许你更改IEnumerables为IQueryables,你可以得到相同的效果? – Ewan