我有多个连接表,带有双键(PersonId,RoleId)。为简单起见,我在Person表中只有一个PersonId。此外,使用EF7,它还不支持EF6所具有的许多优点(例如通过导航属性加入表时的隐含性)。
虽然我可以在SQLite中运行此查询但它没有问题:update PersonRole set RoleId = 2 where PersonId = 1
,我不能在EF中做同样的事情:
var du = context.PersonsRoles.Where(p => p.PersonId == 1).First();
du.RoleId = 2;
context.PersonsRoles.Update(du);
context.SaveChanges(); //get an error here
错误是:“发生了未处理的异常:实体类型'PersonRole'上的属性'RoleId'是密钥的一部分,因此无法修改或标记为已修改。”
(以下评论中的ETA) - 我的模型是:
public class PersonRole
{
public virtual int PersonId { get; set; }
public virtual int RoleId { get; set; }
}
我找到了一个答案,其中包含删除原始行(1,1)的选项,然后重新插入(1,2),但这对我来说似乎效率低下。这真的是修改关系的唯一方法吗?
答案 0 :(得分:1)
您试图在一侧修改多对多关系的密钥。多对多关系在数据库中表示,其中一个表保存关系中双方的外键。
您尝试执行的操作是尝试更改对象的键,但引用仍保留在外键表中,从而导致违反约束 - 因为NN表中的值尚未更新。 / p>
EF7中不允许进行此更改。您应该使用SQL命令来执行此操作,而不是考虑多对多表更新。
答案 1 :(得分:1)
您可以使用此扩展程序删除未选中的内容并将新选择的内容添加到列表中
Partial Class _Default
Inherits Page
<System.Web.Services.WebMethod()>
Public Sub message()
MsgBox("WORKS VB")
End Sub
End Class
使用它看起来像这样
public static void TryUpdateManyToMany<T, TKey>(this DbContext db, IEnumerable<T> currentItems, IEnumerable<T> newItems, Func<T, TKey> getKey) where T : class
{
db.Set<T>().RemoveRange(currentItems.Except(newItems, getKey));
db.Set<T>().AddRange(newItems.Except(currentItems, getKey));
}
public static IEnumerable<T> Except<T, TKey>(this IEnumerable<T> items, IEnumerable<T> other, Func<T, TKey> getKeyFunc)
{
return items
.GroupJoin(other, getKeyFunc, getKeyFunc, (item, tempItems) => new { item, tempItems })
.SelectMany(t => t.tempItems.DefaultIfEmpty(), (t, temp) => new { t, temp })
.Where(t => ReferenceEquals(null, t.temp) || t.temp.Equals(default(T)))
.Select(t => t.t.item);
}