2012-03-12 114 views
1

請看看下面的代碼:EF代碼第一 - 繼承和關係

public class SomeEntity 
{ 
    public int Id { get; set; } 

    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

public class SomeEntityA : SomeEntity 
{ 
    public int Number { get; set; } 
} 

public class SomeEntityB : SomeEntity 
{ 
    public string Text { get; set; } 
} 

public class User 
{ 
    public int Id { get; set; } 
    public int Username { get; set; } 

    public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; } 
} 

我的問題是 - 有沒有辦法來設置FluentApi做出正確上述工作所示的關係?目前,當新的SomeEntityA對象被添加到用戶時,EF會在SomeEntities表中創建一個具有正確設置的User_Id FK的新記錄,但是在SomeEntitesA中,這是一個繼承表,還有一個FK屬性User_Id - 設置爲null,當我嘗試獲取SomeEntites來自User對象的集合 - 它是空的。我明白爲什麼會發生這種情況,但我不確定是否有辦法解決這個問題? ,在這一刻我想到的唯一解決辦法是更換下面的代碼:

public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; } 

有:

public virtual ICollection<SomeEntity> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntity> SomeEntitiesB { get; set; } 

和配置FluentApi。

任何想法將不勝感激。

回答

1

看一看這個問題/答案,這些類具有完全相同的結構,你的,有事情爲什麼不按預期工作的一個詳細的解釋:

Is inheritance of navigation properties supported?

由於Slauma指出,還有一種比較簡單的解決方案來解決這個問題通過執行以下操作(從鏈接的答案被複制,並且要適合你的例子):

public class User 
{ 
    public int Id { get; set; } 
    public int Username { get; set; } 

    // this is necessary to have access to the related SomeEntityAs/SomeEntityBs 
    // also it cant be private otherwise EF will not overload it properly 
    public virtual ICollection<SomeEntity> SomeEntities { get; set; } 

    public IEnumerable<SomeEntityA> SomeEntitiesA { get { return this.SomeEntities.OfType<SomeEntityA>(); } } 
    public IEnumerable<SomeEntityB> SomeEntitiesB { get { return this.SomeEntities.OfType<SomeEntityA>(); } } 
} 
+0

順便說一句:你可以從你的其他答案帶來的解決方案(最後一個代碼片段)這裏的問題。因爲這是一個真正的選擇。它總是會加載所有的基本實體,然後'OfType'會在內存中過濾掉,所以會有潛在的數據加載開銷。但另一方面,在基類中有'User',而不是像我的解決方案那樣在派生類中「重複」。通過一切手段一個有趣的解決方案,值得考慮! (我會upvote :)) – Slauma 2012-03-12 23:24:03

+0

thx的提示,只是更新了答案。 – ntziolis 2012-03-13 00:03:22

+0

謝謝我認爲我會堅持這種方法,但我想更多地瞭解它的性能?即使我將IEnumerable 更改爲IQueryable類型,並且例如使用Take()方法,它是否仍會首先將所有這些實體加載到內存中? – 2012-03-13 15:06:16

1

您建議的解決方案也不起作用,因爲您無法將兩個導航屬性User.SomeEntitiesAUser.SomeEntitiesB關聯到同一端點SomeEntity.User。實際上,你將需要兩個用戶:

public class SomeEntity 
{ 
    public int Id { get; set; } 

    public int UserAId { get; set; } 
    [InverseProperty("SomeEntitiesA")] 
    public virtual User UserA { get; set; } 

    public int UserBId { get; set; } 
    [InverseProperty("SomeEntitiesB")] 
    public virtual User UserB { get; set; } 
} 

但你也可以保持集合類型,因爲他們和移動用戶派生實體:

public class SomeEntity 
{ 
    public int Id { get; set; } 
} 

public class SomeEntityA : SomeEntity 
{ 
    public int Number { get; set; } 

    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

public class SomeEntityB : SomeEntity 
{ 
    public string Text { get; set; } 

    public int UserId { get; set; } 
    public virtual User User { get; set; } 
} 

public class User 
{ 
    public int Id { get; set; } 
    public int Username { get; set; } 

    public virtual ICollection<SomeEntityA> SomeEntitiesA { get; set; } 
    public virtual ICollection<SomeEntityB> SomeEntitiesB { get; set; } 
} 

你並不需要指定[InverseProperty]在這種情況下,因爲約定現在將檢測到正確的導航屬性對。

+0

感謝您的回答,但主要的想法是讓用戶在基地上課,所以當我創建一個視圖來顯示這些實體,我可以顯示用戶名,無論類是A還是B類。 – 2012-03-13 15:04:24