条款Left
and Right
in MapLeftKey
and MapRightKey
在 Fluent API 的多对多映射中可能会被误解,我猜你的问题就是由这种误解引起的。
人们可能会认为这意味着它们描述了多对多连接表中的“左”和“右”列。如果您让 EF Code-First 基于您的 Fluent 映射创建数据库和连接表,实际上就是这种情况。
但当您创建到现有数据库的映射时,情况不一定如此。
为了说明这一点,用一个原型多对多的例子User
-Role
模型假设您有一个现有数据库Users
, Roles
and RoleUsers
table:
现在,您想要将此表模式映射到一个简单的模型:
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 映射Users
实体(你必须这样做,因为按照惯例,上面的模型是一对多的,你不能从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
将抛出您所遇到的异常。当您捕获发送的 SQL 命令时,原因就清楚了SaveChanges
:
exec sp_executesql N'insert [dbo].[RoleUsers]([RoleId], [UserId])
values (@0, @1)
',N'@0 int,@1 int',@0=1,@1=2
因此,EF 希望在连接表中插入一行RoleUsers
with a RoleId
of 1
and a UserId
of 2
这导致外键约束冲突,因为没有用户UserId
2
in the Users
table.
换句话说,上面的映射已经配置了列RoleId
作为表的外键Users
和专栏UserId
作为表的外键Roles
。为了纠正映射,我们必须在连接表中使用“左”列名称MapRightKey
和“右”栏MapLeftKey
:
m.MapLeftKey("UserId");
m.MapRightKey("RoleId");
实际上,查看 Intellisense 的描述可以更清楚地了解“左”和“右”的真正含义:
地图左键
配置左外键的列名称。这
左外键代表在中指定的导航属性
有很多电话。
地图右键
配置右外键的列名称。这
右外键代表在中指定的导航属性
WithMany 调用。
因此,“左”和“右”是指实体在 Fluent 映射中出现的顺序,而不是连接表中的列顺序。表中的顺序实际上并不重要,您可以更改它而不会破坏任何内容,因为INSERT
EF 发送的是“扩展”INSERT
它还包含列名而不仅仅是值。
Perhaps MapFirstEntityKey
and MapSecondEntityKey
这些方法名称的选择可能不会那么误导——或者也许MapSourceEntityKey
and MapTargetEntityKey
.
这是一篇很长的文章,只有两个字。
如果我的猜测是正确的,它与您的问题有任何关系,那么我会说您的第一个映射是不正确的,您只需要第二个正确的映射。