如何通过流畅API实体框架定义许多一对多的关系? [英] How to define Many-to-Many relationship through Fluent API Entity Framework?

查看:116
本文介绍了如何通过流畅API实体框架定义许多一对多的关系?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面是我的模型:

 公共类TMUrl 
{
//许多其他属性$类型关键字
公开名单< b
$ b //唯一的财产;关键字>关键词{获取;集;}
}

公共类关键字
{
//许多其他属性

//只有财产键入TMUrl
公开名单< TMUrl>网址{获取;集;}
}



所以很明显,无论是实体具有多对一一对多的关系。
我选择了流畅的API来讲述这个关系即实体框架

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



但是当我做

  url.Keywords.Add(DBKEY); //其中URL是TMUrl的对象,
// DBKEY是关键字
db.SaveChanges的现有/新的对象();



我得到异常

 同时节省不为他们的关系暴露的外键
性质的实体出错....

的InnerException:

  INSERT语句冲突与外键约束
KeywordMaster_Keyword 。发生于数据库DBNAME的冲突,
表dbo.KeywordMaster,列Id'.The语句已终止。



但是当我从阿瑟赛德藏汉添加配置,一切工作正常。

  modelBuilder.Entity<&关键字GT; 
.HasMany(S = GT; s.URLs)
.WithMany(S = GT; s.Keywords)
.MAP(S = GT;
{
s.MapLeftKey(KeywordId);
s.MapRightKey(UrlId);
s.ToTable(KeywordUrlMapping);
});



为什么会这样?为什么我已经从两个实体,在那里我读到这里 和许多添加配置其他地方,为实体应该做的一个配置。



什么情况下,我应该对这两个关系中所涉及实体添加配置?



我需要了解这一点。为什么。请帮助。


解决方案

条款 MapLeftKey MapRightKey 中的许多一对多映射用流利的API可能被误解,我想你的问题是由这种误解造成的。



有人可能会认为,这意味着他们描述的是左和右的列许多一对多连接表。这实际上是这种情况,如果你让EF代码首先创建数据库和连接表根据您的流利的映射。



但是,当你创建一个映射到它的并不一定如此。现有数据库



要以用户的原型许多一对多的例子说明这一点 - 角色模型假设你有一个用户现有的数据库角色 RoleUsers 表:





现在,要映射这个表架构以一个简单的模型:

 公共类用户
{
公众用户()
{
角色=新的List<作用> ();
}

公众诠释用户ID {搞定;组; }
公共字符串用户名{获得;组; }
公众的ICollection<的角色和GT;角色{搞定;组; }
}

公共类角色
{
公众诠释角色ID {搞定;组; }
公共字符串ROLENAME {搞定;组; }
}

和你添加了用户流利的映射实体(你必须做这种方式,因为按照惯例,上述模型是一个一对多的,你不能从角色开始实体一边,因为它没有用户集合):

 模型构建器。实体<使用者>()
.HasMany(U => u.Roles)
.WithMany()
.MAP(M =>
{
M .MapLeftKey(角色ID); //因为它是左一栏,是不是
m.MapRightKey(用户ID); //因为它是正确的一栏,ISN t将其
m.ToTable(RoleUsers);
});

这映射是错误的,如果你试图把安娜到角色营销......

  VAR安娜= ctx.Users.Find(1); 
变种营销= ctx.Roles.Find(2);

anna.Roles.Add(营销部);

ctx.SaveChanges();



... 的SaveChanges 将抛出完全例外您有。



<预类=郎-SQL prettyprint:当你捕捉与的SaveChanges 发送SQL命令的原因变得清晰-override> EXEC sp_executesql的N'insert [DBO]。[RoleUsers]([角色ID],[用户ID])
值(@ 0,@ 1)
',N @ 0 INT,@ 1诠释',@ 0 = 1,@ 1 = 2

所以, EF想在这里插入行的连接表 RoleUsers 角色ID 1 用户ID 2 这是造成违反外键约束,因为没有用户与用户ID 2 用户表。



在换句话说,映射上面配置了列角色ID 为外键表用户,列用户ID 为外键表角色。为了纠正我们在连接表使用左列名 MapRightKey MapLeftKey <测绘和右列/ code>:

  m.MapLeftKey(用户ID); 
m.MapRightKey(角色ID);



其实看着智能感知的描述使得它更清楚什么是左和右的真正含义:




MapLeftKey



配置列名(个),左外键。
左外键代表了
的hasMany调用中指定的导航属性。



MapRightKey



配置列(S)为右外键的名称。
右外键代表了
WithMany调用中指定的导航属性。




所以,左和右是指在该实体出现在映射流利,不要在连接表中的列顺序的顺序。在表中的顺序其实没关系,你可以改变它不会破坏任何东西,因为插入通过EF发送是一种扩展插入也包含列名,而不是只值。



也许 MapFirstEntityKey MapSecondEntityKey 本来这些方法名不太误导性的选择 - 或者 MapSourceEntityKey MapTargetEntityKey



这是一个漫长的一篇关于这两个词。



如果我的猜测是正确的,那有什么用你的问题都那么我会说,你的第一个映射是不正确的,你只需要在第二个和正确的映射。


Below is my model:

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

So clearly, both the entities have many-to-many relationship. I chose fluent api to tell the entity-framework about this relationship i.e.

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

but when I do

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

I get exception

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.

but when I add Configuration from the otherside aswell, everything works fine. i.e.

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

Why?. Why I've to add configuration from both the entities, where I've read here and many other places, configuration for one of the entities should do.

What is the case, when I should add configuration for both of the entities involved in the relationship?

I need to understand this. Why. Please help.

解决方案

The terms Left and Right in MapLeftKey and MapRightKey in the many-to-many mapping with Fluent API can be misunderstood and I guess your problem is caused by this misunderstanding.

One might think that it means they describe the columns that are "left" and "right" in the many-to-many join table. That's actually the case if you let EF Code-First create the database and join table based on your Fluent mapping.

But it's not necessarily the case when you create a mapping to an existing database.

To illustrate this with the prototypic many-to-many example of a User-Role model assume you have an existing database with a Users, Roles and RoleUsers table:

Now, you want to map this table schema to a simple model:

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

And you add the Fluent mapping for the Users entity (you must do it this way, because by convention the model above would be one-to-many and you can't start from the Role entity side because it has no Users collection):

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

This mapping is wrong and if you try to put "Anna" into role "Marketing"...

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

anna.Roles.Add(marketing);

ctx.SaveChanges();

...SaveChanges will throw exactly the exception you are having. The reason becomes clear when you capture the SQL command that is sent with SaveChanges:

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

So, EF wants to insert here a row into the join table RoleUsers with a RoleId of 1 and a UserId of 2 which is causing the foreign key constraint violation because there is no user with UserId 2 in the Users table.

In other words, the mapping above has configured the column RoleId as the foreign key to table Users and the column UserId as the foreign key to table Roles. In order to correct the mapping we have to use the "left" column name in the join table in MapRightKey and the "right" column in MapLeftKey:

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

Actually looking at Intellisense the description makes it clearer what "Left" and "Right" really mean:

MapLeftKey

Configures the name of the column(s) for the left foreign key. The left foreign key represents the navigation property specified in the HasMany call.

MapRightKey

Configures the name of the column(s) for the right foreign key. The right foreign key represents the navigation property specified in the WithMany call.

So, "Left" and "Right" refer to the order in which the entities appear in the Fluent mapping, not to the column order in the join table. The order in the table actually doesn't matter, you can change it without breaking anything because the INSERT sent by EF is an "extended" INSERT that also contains the column names and not only the values.

Perhaps MapFirstEntityKey and MapSecondEntityKey would have been a less misleading choice of those method names - or maybe MapSourceEntityKey and MapTargetEntityKey.

This was a long post about two words.

If my guess is right that it has anything to do with your problem at all then I would say that your first mapping is incorrect and that you only need the second and correct mapping.

这篇关于如何通过流畅API实体框架定义许多一对多的关系?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆