2013-05-10 87 views
31

下面是我的模型:如何通過Fluent API Entity Framework定義多對多關係?

public class TMUrl 
{ 
    //many other properties 

    //only property with type Keyword 
    public List<Keyword> Keywords{get;set;} 
} 

public class Keyword 
{ 
    //many other properties 

    //only property with type TMUrl 
    public List<TMUrl> Urls{get;set;} 
} 

所以很明顯,無論是實體有許多一對多的關係。 我選擇了流暢的API來講述即

modelBuilder.Entity<TMUrl> 
       .HasMany(s => s.Keywords) 
       .WithMany(s => s.URLs).Map(s => 
       { 
        s.MapLeftKey("KeywordId"); 
        s.MapRightKey("UrlId"); 
        s.ToTable("KeywordUrlMapping"); 
       }); 

這種關係的實體框架,但是當我做

url.Keywords.Add(dbKey); //where url is object of TMUrl, 
         //dbKey is an existing/new object of Keyword 
db.SaveChanges(); 

我得到異常

An error occurred while saving entities that do not expose foreign key 
properties for their relationships.... 

的InnerException:

The INSERT statement conflicted with the FOREIGN KEY constraint 
"KeywordMaster_Keyword". The conflict occurred in database "DbName", 
table "dbo.KeywordMaster", column 'Id'.The statement has been terminated. 

,但是當我從其他人添加配置時,一切正常。 即

modelBuilder.Entity<KeyWord> 
     .HasMany(s => s.URLs) 
     .WithMany(s => s.Keywords) 
     .Map(s => 
       { 
        s.MapLeftKey("KeywordId"); 
        s.MapRightKey("UrlId"); 
        s.ToTable("KeywordUrlMapping"); 
       }); 

爲什麼?爲什麼我必須從兩個實體中添加配置,其中我讀過here和其他許多地方,其中一個實體應該配置。

什麼情況下,我應該爲兩個關係中涉及的實體添加配置?

我需要了解這一點。爲什麼。請幫忙。

+0

「*有關詳細信息,請參閱InnerException *」。你是否?對於這個很少有用的例外,內部例外是非常重要的。 – Slauma 2013-05-10 21:16:31

+0

@Slauma,我已經用內部異常更新了這個問題,但請注意,從兩側添加關係都會使其工作。 – 2013-05-10 21:43:38

+0

有趣的問題是,如果*僅*第二個映射(沒有第一個映射)會使它工作。如果是的話,我會懷疑映射表中的'KeywordId'列實際上是表'URLs'而不是'Keywords'的外鍵。 (只有當這是一個具有手動創建關係的現有數據庫時纔可能,而不是如果您使用Code-First創建了數據庫。) – Slauma 2013-05-10 21:50:54

回答

109

條款在MapLeftKeyLeftRight,並在許多一對多映射用流利的API MapRightKey可能被誤解,我想你的問題是由這種誤解造成的。

有人可能會認爲這意味着他們描述了多對多連接表中「左」和「右」的列。實際上,如果您讓EF Code-First根據您的Fluent映射創建數據庫並連接表,那就是這種情況。

但是,當您創建到現有數據庫的映射時不一定如此。

要使用User的原型許多一對多的例子說明這一點 - Role模型假設你有一個UsersRolesRoleUsers臺現有的數據庫:

Many-to-many database tables

現在,你想將此表格架構映射到一個簡單模型:

public class User 
{ 
    public User() 
    { 
     Roles = new List<Role>(); 
    } 

    public int UserId { get; set; } 
    public string UserName { get; set; } 
    public ICollection<Role> Roles { get; set; } 
} 

public class Role 
{ 
    public int RoleId { get; set; } 
    public string RoleName { get; set; } 
} 

然後您爲添加Fluent映射實體(你必須做這種方式,因爲按照慣例,上述模型是一個一對多的,你不能從Role實體身邊做起,因爲它沒有Users集合):

modelBuilder.Entity<User>() 
    .HasMany(u => u.Roles) 
    .WithMany() 
    .Map(m => 
    { 
     m.MapLeftKey("RoleId"); // because it is the "left" column, isn't it? 
     m.MapRightKey("UserId"); // because it is the "right" column, isn't it? 
     m.ToTable("RoleUsers"); 
    }); 

這映射是錯誤的,如果你試圖把「安娜」的角色「市場營銷」......

var anna = ctx.Users.Find(1); 
var marketing = ctx.Roles.Find(2); 

anna.Roles.Add(marketing); 

ctx.SaveChanges(); 

... SaveChanges將拋出正是你所具有的異常。當你捕獲與SaveChanges發送SQL命令的原因變得清晰:

exec sp_executesql N'insert [dbo].[RoleUsers]([RoleId], [UserId]) 
values (@0, @1) 
',N'@0 int,@1 int',@0=1,@1=2 

所以,EF想在這裏插入一行到連接表RoleUsers1一個RoleId2一個UserId這是造成外鍵約束衝突,因爲Users表中沒有UserId2的用戶。

換言之,上述的映射已配置的列RoleId爲外鍵表Users和作爲外鍵表RolesUserId。爲了糾正MapLeftKey我們必須在連接表中MapRightKey使用「左」列名的映射和「右」列:

 m.MapLeftKey("UserId"); 
     m.MapRightKey("RoleId"); 

其實在看智能感知的描述使得它更清楚什麼是「左「和 」右「 的真正含義:

MapLeftKey

配置列(個),左外鍵的名稱。 左側外鍵代表在 HasMany調用中指定的導航屬性。

MapRightKey

配置列(個),右外鍵的名稱。 右側外鍵代表在 WithMany調用中指定的導航屬性。

所以,「左」和「右」是指實體出現在Fluent映射中的順序,而不是連接表中的列順序。表格中的順序實際上並不重要,因爲EF發送的INSERT是一個「擴展」INSERT,它也包含列名稱而不僅僅是值,所以可以更改它而不會破壞任何內容。

也許MapFirstEntityKeyMapSecondEntityKey本來這些方法名的少誤導性的選擇 - 或者MapSourceEntityKeyMapTargetEntityKey

這是一篇長約兩個單詞。

如果我的猜測與你的問題有關,那麼我會說你的第一個映射是不正確的,你只需要第二個正確的映射。

+9

+1對於MapLeftKey和MapRightKey – moke 2013-09-27 01:06:35

+3

+1的解釋有深入的討論和解釋。花了我大約20左右調試堆棧跟蹤視圖來找出你在一個長篇文章中解釋什麼。 – GoldBishop 2013-12-28 03:08:37

+0

在我的expirience中,它只是oposit,LeftKey是WithMany單元格,RightKey是HasMany單元格。這裏還提到:https://msdn.microsoft.com/en-us/data/hh134698.aspx – IFink 2016-03-08 12:12:29

相關問題