2

我使用EF 4.1 Code First並嘗試對以下模型進行建模。EF 4.1:映射與複合鍵和共享列的多對多關係?

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

public class Banana 
{ 
    public int AppleId {get;set;} 
    public int Id {get;set;} 
    public virtual ICollection<Coconut> Coconuts {get;set;} 
} 

public class Coconuts 
{ 
    public int AppleId {get;set;} 
    public int Id {get;set;} 
    public virtual ICollection<Banana> Bananas {get;set;} 
} 

數據庫看起來像這樣。 Fruit

這是一個不遵循EF約定的現有模式,所以我使用Fluent API將實體映射到數據庫。映射看起來像這樣。

public class BananaMapping : EntityTypeConfiguration<Banana> 
{ 
    public BananaMapping() 
    { 
     HasKey(e => new { e.AppleId, e.Id }) 
      .ToTable("Bananas", "fruit"); 
     Property(e => e.Id) 
      .HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); 

     HasMany(e => e.Coconuts) 
      .WithMany(s => s.Bananas) 
      .Map(l => 
        { 
         l.ToTable("BananaCoconuts", "fruit"); 
         l.MapLeftKey("AppleId", "BananaId"); 
         l.MapRightKey("AppleId", "CoconutId"); 
        }); 
    } 

(蘋果和椰子被映射過,但這裏不再贅述) 如果我離開它這樣,它會產生,因爲共享列的MetadataException。 "Schema specified is not valid. Errors: (110,6) : error 0019: Each property name in a type must be unique. Property name 'AppleId' was already defined."

爲了突破這一點,我創建了BananaCoconuts計算列,僅僅暴露了AppleId一個不同名稱的副本,並把它稱爲BananaAppleId。我離開了FKS單獨(明顯),並改變了映射到這個樣子......

HasMany(e => e.Coconuts) 
    .WithMany(s => s.Bananas) 
    .Map(l => 
     { 
      l.ToTable("BananaCoconuts", "fruit"); 
      l.MapLeftKey("BananaAppleId", "BananaId"); 
      l.MapRightKey("AppleId", "CoconutId"); 
     } 
    ); 

雖然有點臭,肯定hacktastic,但它確實讓我過去MetadataException,直到我試圖從添加一個新的鏈接碼。

var banana = dataContext.FindBanana(appleId, bananaId); 
var coconut = dataContext.FindCoconut(appleId, coconutId); 
banana.Coconuts.Add(coconut); 
dataContext.SaveChanges(); 

保存更改拋出一個DbUpdateException

An error occurred while saving entities that do not expose foreign key properties for their relationships. The EntityEntries property will return null because a single entity cannot be identified as the source of the exception. Handling of exceptions while saving can be made easier by exposing foreign key properties in your entity types. See the InnerException for details. 

和內部(一些例外下來,實際上)...

{"The column \"BananaAppleId\" cannot be modified because it is either a computed column or is the result of a UNION operator."} 

現在我的想法。 :)數據庫模式準確地模擬我們需要的東西(除了計算列)。處理這個問題的最好方法是什麼?我並不是瘋狂地將BananaAppleId設置爲「真實」列,更改外鍵以及重複存儲的數據,這些數據應該不會同步。

回答

3

連接表需要有4列作爲主鍵,每一列都是主表的外鍵。由於EF會通過發送所有4個列值來插入記錄,因此無法將列設置爲計算值。所以在你的情況下

HasMany(e => e.Coconuts) 
    .WithMany(s => s.Bananas) 
    .Map(l => 
     { 
      l.ToTable("BananaCoconuts", "fruit"); 
      l.MapLeftKey("BananaAppleId", "BananaId"); 
      l.MapRightKey("CoconutAppleId", "CoconutId"); 
     } 
    ); 

否則,你必須映射連接表作爲一個單獨的實體。

+0

謝謝。這就是我們所做的,我們在 BananaAppleId和CoconutAppleId之間加上了一個檢查約束,這樣它們必須保持同步。 – Josh