Entity Framework Core 不会更新 ICollection
Posted
技术标签:
【中文标题】Entity Framework Core 不会更新 ICollection【英文标题】:Entity Framework Core will not update ICollection 【发布时间】:2020-04-28 08:09:10 【问题描述】:尝试对具有嵌套列表的实体执行更新。无论我做什么,我都会不断收到此错误。我试过这个:Updating Nested Objects in Entity Framework 和这个:entity framework update nested objects
数据库操作预计会影响 1 行,但实际上会影响 0 行。自加载实体以来,数据可能已被修改或删除。有关理解和处理乐观并发异常的信息,请参阅 http://go.microsoft.com/fwlink/?LinkId=527962。
“TypeName”:“Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException”
插入新行就可以了。但不更新。
public class BuyGroup
[Key]
public Guid Id get; set;
[Required]
[Column(TypeName = "nvarchar(150)")]
public string Name get; set;
public virtual ICollection<Item> Items get; set; = new List<Item>();
public class Item
[Key]
public Guid Id get; set;
[Required]
[Column(TypeName = "nvarchar(100)")]
public string Name get; set;
public BuyGroup BuyGroup get; set;
存储库:
public async Task<Guid> Save(Entities.BuyGroup model)
using (var dc = _dataContext())
// this is ok, i get existing item with Items collection populated
var existing = await Get(model.Id);
if (existing != null)
existing.Name = model.Name;
... // overwrite properties
existing.Items = model.Items; // overwrite Items colletion
dc.BuyGroups.Update(existing).State = EntityState.Modified;
else
await dc.BuyGroups.AddAsync(model);
// blows up here when existing != null
await dc.SaveChangesAsync();
编辑:
添加Get()
方法
using (var dc = _dataContext())
return await dc.BuyGroups.FirstOrDefaultAsync(x => x.Id == id);
EDIT2:
使用相同的上下文仍然不能解决我的问题:
using (var dc = _dataContext())
var existing = await dc.BuyGroups.FirstOrDefaultAsync(x => x.Id == id); // same context
if (existing != null)
existing.Items.Add(new Item .....):
dc.ByGroups.Entry(existing).State = EntityState.Modified;
else
await dc.BuyGroups.AddAsync(model);
await dc.SaveChangesAsync();
【问题讨论】:
如果你将Items
设为非虚拟,它会起作用吗?
不 :(。不起作用
为什么两者都需要 1) dc.BuyGroups.Update(existing).State = EntityState.Modified; 2) 等待 dc.SaveChangesAsync();
用dc.BuyGroups.Update(existing);
替换dc.BuyGroups.Update(existing).State = EntityState.Modified;
试过了。没用
【参考方案1】:
我的印象是,由于您正在调用函数 _dataContext()
,而不是调用刚刚 _dataContext 的受保护实例,因此您可能在 get 和 save 方法中创建了一个新上下文。
因为,get 和 save 方法使用单独的 DbContexts
,所以当您 existing.Items = model.Items;
时,您使用的是附加到单独上下文的项目。
有很多方法可以解决这个问题,但我个人只会创建接受 dbContext 的受保护方法,因此您不必担心将实体附加到上下文。
protected BuyGroup GetImplementation(MyDbContext context, int id)
return await context.BuyGroups.FirstOrDefaultAsync(x => x.Id == id);
然后在你的保存方法中你可以直接调用:
var existing = await this.GetImplementation(dc, model.Id);
为编辑而编辑
您将新项目设置为修改而不是添加
existing.Items.Add(new Item .....):
//You shouldn't do this for added items
//dc.ByGroups.Entry(existing).State = EntityState.Modified;
【讨论】:
但我使用相同的上下文获取。请参阅Edit2。 @ShaneKm 您正在覆盖添加的状态以修改后 在注释掉 Modified line state() 后仍然得到相同的异常。也尝试过 State = added 但会引发不同的异常 @ShaneKm 听起来您多次附加到上下文中。每个实体*在应用于上下文时必须具有正确的状态。请发布您的完整代码,不要省略详细信息 例如看到这个answer【参考方案2】:您想将模型中的所有项目分配给另一个表中的一个实体吗?这是一个设计错误。
此外,我不确定您是否可以在一个实体中替换整个集合。您必须清除它们并添加新项目。您正在将 DbSet
分配给现有的。物品,这绝对是不可能的。
编辑
另一件事:您为“现有”创建了一个新的上下文,并从其他来源附加了一些东西。也许您的Items
来自另一个上下文。它们需要附加到这个 dc
上下文。
【讨论】:
你的意思是不可能?您将如何对嵌套集合执行更新? 你所做的是,你把整个集合扔掉,你把它扔进垃圾箱,覆盖existing.Items
。您可以调用 Add/Remove 来插入或删除某些内容。您不需要更新集合中已有的元素,它们始终是最新的 - 因为它们没有两个实例。您确定您的嵌套集合不是最新的吗?因为如果一切都配置好,这是自动完成的。你在model.Items中插入一些东西,这个Item就会出现在所有相关实体中。【参考方案3】:
这是一个长镜头,如果你的电脑爆炸,我不承担责任,试试这个:
public async Task<Guid> Save(Entities.BuyGroup model)
using (var dc = _dataContext())
var existing = await Get(model.Id);
if (existing != null)
dc.ByGroups.Entry(model).State = EntityState.Modified;
else
await dc.BuyGroups.AddAsync(model);
await dc.SaveChangesAsync();
【讨论】:
不起作用。我试过像这样向 Items 集合添加一个新项目:existing.Items.Add(new Item Id = Guid.NewGuid(), Name = "Test" );然后 Entry(model).State = 已修改。但我仍然得到一个例外。如果我删除 Add(new item) 它会通过并且只更新 BuyGroup 类的简单道具而不是 Items 集合 好吧,太糟糕了,它不起作用,你可以试试MS docs page 它有 ASP.NET Core Web API 的方法,特别是 PUT 方法可能会有所帮助,因为它与什么有一些相似之处你想做。以上是关于Entity Framework Core 不会更新 ICollection的主要内容,如果未能解决你的问题,请参考以下文章
Entity Framework Core 2.0 Add-Migration 不会创建任何迁移文件
使用内置 Linq to SQL 驱动程序在 LinqPad 中运行 Entity Framework Core 查询的更简单方法?
Entity Framework Core:列、参数或变量 #4:找不到数据类型 bool