2015-04-16 36 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