【问题标题】:Entity Framework Core will not update ICollectionEntity Framework Core 不会更新 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;
  • 试过了。没用

标签: c# .net-core entity-framework-core


【解决方案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 方法可能会有所帮助,因为它与什么有一些相似之处你想做。
猜你喜欢
  • 2020-08-09
  • 1970-01-01
  • 2023-03-16
  • 2017-09-17
  • 2017-02-11
  • 2018-04-07
  • 1970-01-01
  • 2020-12-06
  • 2020-02-06
相关资源
最近更新 更多