Entity framework 实体框架核心多对多更新
我们正在将现有的MVC6 EF6应用程序移植到Core EF Core中是否有更新多对多关系的简单方法 我的旧代码来自EF6,在那里我们清除列表并用新数据覆盖它不再工作Entity framework 实体框架核心多对多更新,entity-framework,asp.net-core,Entity Framework,Asp.net Core,我们正在将现有的MVC6 EF6应用程序移植到Core EF Core中是否有更新多对多关系的简单方法 我的旧代码来自EF6,在那里我们清除列表并用新数据覆盖它不再工作 var model = await _db.Products.FindAsync(vm.Product.ProductId); model.Colors.Clear(); model.Colors = _db.Colors.Where(x => vm.ColorsSelected.Contains(x.ColorId)
var model = await _db.Products.FindAsync(vm.Product.ProductId);
model.Colors.Clear();
model.Colors = _db.Colors.Where(x =>
vm.ColorsSelected.Contains(x.ColorId)).ToList();
这对你有用 创建一个类以在其中建立关系:
public class ColorProduct
{
public int ProductId { get; set; }
public int ColorId { get; set; }
public Color Color { get; set; }
public Product Product { get; set; }
}
将ColorProduct
集合添加到您的Product
和Color
类中:
public ICollection<ColorProduct> ColorProducts { get; set; }
为了避免上述答案中的LINQ地狱,模板化的“Except”方法可以重写为:
public static IEnumerable<TEntity> LeftComplementRight<TEntity, TKey>(
this IEnumerable<TEntity> left,
IEnumerable<TEntity> right,
Func<TEntity, TKey> keyRetrievalFunction)
{
var leftSet = left.ToList();
var rightSet = right.ToList();
var leftSetKeys = leftSet.Select(keyRetrievalFunction);
var rightSetKeys = rightSet.Select(keyRetrievalFunction);
var deltaKeys = leftSetKeys.Except(rightSetKeys);
var leftComplementRightSet = leftSet.Where(i => deltaKeys.Contains(keyRetrievalFunction.Invoke(i)));
return leftComplementRightSet;
}
公共静态IEnumerable leftright(
这是一个数不清的左边,
我数不清的权利,
Func键检索函数)
{
var leftSet=left.ToList();
var rightSet=right.ToList();
var leftSetKeys=leftSet.Select(keyRetrievalFunction);
var rightSetKeys=righset.Select(keyRetrievalFunction);
var deltaKeys=左设置键。除(右设置键)外;
var leftcomplementrighset=leftSet.Where(i=>deltaKeys.Contains(keyRetrievalFunction.Invoke(i));
返回leftrighset;
}
此外,可以更新UpdateManyToMany方法,以包括已修改的实体:
public void UpdateManyToMany<TDependentEntity, TKey>(
IEnumerable<TDependentEntity> dbEntries,
IEnumerable<TDependentEntity> updatedEntries,
Func<TDependentEntity, TKey> keyRetrievalFunction)
where TDependentEntity : class
{
var oldItems = dbEntries.ToList();
var newItems = updatedEntries.ToList();
var toBeRemoved = oldItems.LeftComplementRight(newItems, keyRetrievalFunction);
var toBeAdded = newItems.LeftComplementRight(oldItems, keyRetrievalFunction);
var toBeUpdated = oldItems.Intersect(newItems, keyRetrievalFunction);
this.Context.Set<TDependentEntity>().RemoveRange(toBeRemoved);
this.Context.Set<TDependentEntity>().AddRange(toBeAdded);
foreach (var entity in toBeUpdated)
{
var changed = newItems.Single(i => keyRetrievalFunction.Invoke(i).Equals(keyRetrievalFunction.Invoke(entity)));
this.Context.Entry(entity).CurrentValues.SetValues(changed);
}
}
public void updatemanytomy(
IEnumerable dbEntries,
i无数次的尝试,
Func键检索函数)
其中TDependentity:类
{
var oldItems=dbEntries.ToList();
var newItems=updatedEntries.ToList();
var toBeRemoved=oldItems.LeftComplementRight(newItems,keyRetrievalFunction);
var tobeaded=newItems.LeftComplementRight(oldItems,keyRetrievalFunction);
var toBeUpdated=oldItems.Intersect(newItems,keyRetrievalFunction);
this.Context.Set();
this.Context.Set().AddRange(tobedded);
foreach(待更新的var实体)
{
var changed=newItems.Single(i=>keyRetrievalFunction.Invoke(i).Equals(keyRetrievalFunction.Invoke(entity));
this.Context.Entry(entity).CurrentValues.SetValues(已更改);
}
}
它使用另一个自定义模板“Intersect”函数来查找两个集合的交点:
public static IEnumerable<TEntity> Intersect<TEntity, TKey>(
this IEnumerable<TEntity> left,
IEnumerable<TEntity> right,
Func<TEntity, TKey> keyRetrievalFunction)
{
var leftSet = left.ToList();
var rightSet = right.ToList();
var leftSetKeys = leftSet.Select(keyRetrievalFunction);
var rightSetKeys = rightSet.Select(keyRetrievalFunction);
var intersectKeys = leftSetKeys.Intersect(rightSetKeys);
var intersectionEntities = leftSet.Where(i => intersectKeys.Contains(keyRetrievalFunction.Invoke(i)));
return intersectionEntities;
}
公共静态IEnumerable Intersect(
这是一个数不清的左边,
我数不清的权利,
Func键检索函数)
{
var leftSet=left.ToList();
var rightSet=right.ToList();
var leftSetKeys=leftSet.Select(keyRetrievalFunction);
var rightSetKeys=righset.Select(keyRetrievalFunction);
var intersectKeys=leftSetKeys.Intersect(rightSetKeys);
var intersectionenties=leftSet.Where(i=>intersectKeys.Contains(keyRetrievalFunction.Invoke(i));
返回交叉实体;
}
哇,这太棒了。我可以在我的所有项目中使用此扩展。感谢您及时的回答。此解决方案的关键部分(以及操作代码中的问题)是Include
call.AddRange没有Func getKey参数这是一种好的有效方法吗?或者您是否找到了其他可能的方法?为什么要检查null和default是否相等?我想只有默认值才足够(因为ref类型的默认值可以为null)。什么是不再工作?它不再产生预期的结果。实体框架核心的更改跟踪方式有所不同。我遇到了类似的问题,尝试了下面的各种答案,最后通过确保对子集合调用了Include()
和thenclude()
(Colors
)。简单得多。这篇文章也很有用:现在还不清楚“不再有效”是什么意思。如果关系的数量有限,并且可以使用EF core进行替换,那么替换关系是最简单的方法。
public void UpdateManyToMany<TDependentEntity, TKey>(
IEnumerable<TDependentEntity> dbEntries,
IEnumerable<TDependentEntity> updatedEntries,
Func<TDependentEntity, TKey> keyRetrievalFunction)
where TDependentEntity : class
{
var oldItems = dbEntries.ToList();
var newItems = updatedEntries.ToList();
var toBeRemoved = oldItems.LeftComplementRight(newItems, keyRetrievalFunction);
var toBeAdded = newItems.LeftComplementRight(oldItems, keyRetrievalFunction);
var toBeUpdated = oldItems.Intersect(newItems, keyRetrievalFunction);
this.Context.Set<TDependentEntity>().RemoveRange(toBeRemoved);
this.Context.Set<TDependentEntity>().AddRange(toBeAdded);
foreach (var entity in toBeUpdated)
{
var changed = newItems.Single(i => keyRetrievalFunction.Invoke(i).Equals(keyRetrievalFunction.Invoke(entity)));
this.Context.Entry(entity).CurrentValues.SetValues(changed);
}
}
public static IEnumerable<TEntity> Intersect<TEntity, TKey>(
this IEnumerable<TEntity> left,
IEnumerable<TEntity> right,
Func<TEntity, TKey> keyRetrievalFunction)
{
var leftSet = left.ToList();
var rightSet = right.ToList();
var leftSetKeys = leftSet.Select(keyRetrievalFunction);
var rightSetKeys = rightSet.Select(keyRetrievalFunction);
var intersectKeys = leftSetKeys.Intersect(rightSetKeys);
var intersectionEntities = leftSet.Where(i => intersectKeys.Contains(keyRetrievalFunction.Invoke(i)));
return intersectionEntities;
}