实体框架核心不会更新ICollection

时间:2020-01-10 16:40:27

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

尝试对具有嵌套列表的实体执行更新。无论我做什么,我都会不断收到此错误。我已经尝试过这个: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();
}

3 个答案:

答案 0 :(得分:2)

您想将模型中的所有项分配给另一个表中的一个实体?这是一个设计错误。

此外,我不确定您是否可以在一个实体中替换整个集合。您必须清除它们并添加新项目。您正在为现有分配一个DbSet。物品,那绝对是不可能的。

修改 另一件事:您为“现有”创建新的上下文,并附加了其他来源的内容。也许您的Items来自另一个上下文。它们需要附加到此dc上下文中。

答案 1 :(得分:1)

这是一个远景,如果您的PC发生爆炸,我不承担任何责任,请尝试以下操作:

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();
    }
}

答案 2 :(得分:1)

给我的印象是,由于您正在调用函数_dataContext(),而不是调用_dataContext的受保护实例,您可能是在get和save方法中创建了一个新上下文。

因为,获取和保存方法使用的是单独的DbContexts,所以当您使用existing.Items = model.Items;时,您使用的是附加到单独的上下文的项目。

有很多方法可以解决此问题,但是就我个人而言,我将创建受保护的方法来接受dbContext,因此您不必担心将实体附加到上下文。

protected BuyGroup GetImplementation(MyDbContext context, int id)
{
    return await context.BuyGroups.FirstOrDefaultAsync(x => x.Id == id);
}

然后在您的save方法中,您可以改为调用:

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;