2013-05-10 37 views
31

Dưới đây là mô hình của tôi:Làm cách nào để xác định mối quan hệ Nhiều-với-Nhiều qua Khuôn khổ thực thể API thông thạo?

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;} 
} 

Vì vậy, rõ ràng, cả hai đối tượng có nhiều-nhiều mối quan hệ. tôi đã chọn api thông thạo nói với các thực thể khuôn khổ về mối quan hệ này tức là

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

nhưng khi tôi làm

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

tôi nhận được ngoại lệ

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. 

nhưng khi tôi thêm Cấu hình từ những người khác, mọi thứ đều hoạt động tốt. ví dụ:

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

Tại sao ?. Tại sao tôi phải thêm cấu hình từ cả hai thực thể, nơi tôi đã đọc here và nhiều địa điểm khác, cấu hình cho một trong các thực thể nên làm.

Trường hợp là gì, khi tôi nên thêm cấu hình cho cả hai thực thể có liên quan đến mối quan hệ?

Tôi cần hiểu điều này. Tại sao. Hãy giúp tôi.

+0

"* Xem InnerException để biết chi tiết *". Bạn đã? Đối với ngoại lệ hiếm khi hữu ích này, ngoại lệ bên trong thực sự quan trọng cần biết. – Slauma

+0

@Slauma, tôi đã cập nhật câu hỏi với ngoại lệ bên trong, nhưng lưu ý rằng việc thêm mối quan hệ từ cả hai phía làm cho nó hoạt động. –

+0

Câu hỏi thú vị sẽ là nếu * chỉ * ánh xạ thứ hai (không có ánh xạ đầu tiên) sẽ làm cho nó hoạt động. Nếu có, tôi nghi ngờ rằng cột 'KeywordId' trong bảng ánh xạ thực sự là khóa ngoài để bảng' URL' và không phải là 'Từ khoá'. (Chỉ nên có nếu đây là một DB hiện có với các mối quan hệ được tạo theo cách thủ công, không phải nếu bạn đã tạo DB bằng Mã-Đầu tiên.) – Slauma

Trả lời

109

Các điều khoản LeftRight trong MapLeftKeyMapRightKey trong việc lập bản đồ nhiều-nhiều với API thạo có thể được hiểu lầm và tôi đoán vấn đề của bạn là do sự hiểu lầm này.

Người ta có thể nghĩ rằng điều đó có nghĩa là họ mô tả các cột "trái" và "phải" trong bảng kết nối nhiều người tham gia. Đó thực sự là trường hợp nếu bạn cho EF Code-First tạo cơ sở dữ liệu và tham gia bảng dựa trên bản đồ Fluent của bạn.

Nhưng nó không nhất thiết phải là trường hợp khi bạn tạo ánh xạ tới cơ sở dữ liệu hiện có.

Để minh họa điều này với prototypic nhiều-nhiều ví dụ về một User - mô hình Role giả sử bạn có một cơ sở dữ liệu hiện có với một bảng Users, RolesRoleUsers:

Many-to-many database tables

Bây giờ, bạn muốn để ánh xạ lược đồ bảng này thành một mô hình đơn giản:

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; } 
} 

Và bạn thêm ánh xạ Fluent cho Users thực thể (bạn phải làm theo cách này, vì theo quy ước mô hình trên sẽ là một-nhiều và bạn không thể bắt đầu từ phía bên Role thực thể bởi vì nó không có Users bộ sưu tập):

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"); 
    }); 

này lập bản đồ sai và nếu bạn cố gắng đặt "Anna" vào vai trò "Tiếp thị" ...

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

anna.Roles.Add(marketing); 

ctx.SaveChanges(); 

... SaveChanges sẽ ném chính xác ngoại lệ bạn đang gặp phải. Lý do trở nên rõ ràng khi bạn nắm bắt được lệnh SQL được gửi với SaveChanges:

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

Vì vậy, EF muốn chèn đây một hàng vào bảng tham gia RoleUsers với một RoleId của 1UserId của 2 mà đang gây ra vi phạm ràng buộc khóa ngoài vì không có người dùng nào có UserId2 trong bảng Users.

Nói cách khác, các bản đồ trên đã cấu hình cột RoleId là chìa khóa nước ngoài để bảng Users và cột UserId là chìa khóa nước ngoài để bảng Roles. Để sửa bản đồ, chúng ta phải sử dụng "trái" tên cột trong bảng tham gia MapRightKey và cột "đúng" trong MapLeftKey:

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

Trên thực tế nhìn vào Intellisense mô tả làm cho nó rõ ràng hơn những gì "Left "và "phải" thực sự có nghĩa là:

MapLeftKey

Cấu hình tên của cột (s) cho chính nước ngoài trái. khóa ngoài bên trái đại diện cho thuộc tính điều hướng được chỉ định trong các cuộc gọi của HasMany .

MapRightKey

Cấu hình tên của cột (s) cho chính nước ngoài phải. khóa ngoài bên phải đại diện cho thuộc tính điều hướng được chỉ định trong các cuộc gọi WithMany.

Vì vậy, "Trái" và "Phải" tham chiếu đến thứ tự các thực thể xuất hiện trong bản đồ Thông thạo, không theo thứ tự cột trong bảng tham gia. Thứ tự trong bảng thực sự không quan trọng, bạn có thể thay đổi nó mà không vi phạm bất cứ điều gì bởi vì INSERT được gửi bởi EF là "mở rộng" INSERT cũng chứa các tên cột và không chỉ các giá trị.

Có lẽ MapFirstEntityKeyMapSecondEntityKey sẽ là lựa chọn ít gây nhầm lẫn hơn cho các tên phương pháp đó - hoặc có thể MapSourceEntityKeyMapTargetEntityKey.

Đây là một bài đăng dài về hai từ.

Nếu dự đoán của tôi là có liên quan đến vấn đề của bạn thì tôi sẽ nói rằng bản đồ đầu tiên của bạn không chính xác và bạn chỉ cần ánh xạ thứ hai và chính xác.

+9

+1 cho lời giải thích của MapLeftKey và MapRightKey – moke

+3

+1 để thảo luận sâu và giải thích. Đã cho tôi khoảng 20 hoặc hơn Debug stack lượt xem theo dõi để tìm ra những gì bạn đã giải thích trong một bài viết dài. – GoldBishop

+0

như trong thời hạn của tôi, nó chỉ là oposit, LeftKey là cho ô WithMany, và RightKey là cho tế bào HasMany. cũng đề cập ở đây: https://msdn.microsoft.com/en-us/data/hh134698.aspx – IFink

Các vấn đề liên quan