Entity Framework Core will not update ICollection

.net-core c# entity-framework-core

Question

Trying to perform an update on an entity with nested list. I keep getting this error no matter what I do. I've tried this: Updating Nested Objects in Entity Framework and this: entity framework update nested objects

Database operation expected to affect 1 row(s) but actually affected 0 row(s). Data may have been modified or deleted since entities were loaded. See http://go.microsoft.com/fwlink/?LinkId=527962 for information on understanding and handling optimistic concurrency exceptions.

"TypeName": "Microsoft.EntityFrameworkCore.DbUpdateConcurrencyException"

Inserting a new row works just fine. But not update.

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

Repository:

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

EDIT:

Adding Get() method

{
    using (var dc = _dataContext())
    {
        return await dc.BuyGroups.FirstOrDefaultAsync(x => x.Id == id);
    }
}

EDIT2:

Using the same context still does not solve my issue:

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();
}
1
1
1/10/2020 7:43:56 PM

Accepted Answer

I'm under the impression that since you're invoking a function _dataContext(), instead of calling to a protected instance of the just _dataContext, You're probably creating a new context in the get and save methods.

Since, get and save methods are using seperate DbContexts so when you existing.Items = model.Items; You're using items that are attached to a seperate context.

There are a lot of ways to solve this, but personally I would just create protected methods that accept the dbContext, so you don't have to worry about attaching the entities to the context.

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

Then in your save method you can just call instead:

var existing = await this.GetImplementation(dc, model.Id);

Edit For Edit

You're setting the new item to modified instead of added

existing.Items.Add(new Item{ .....}):
//You shouldn't do this for added items
//dc.ByGroups.Entry(existing).State = EntityState.Modified;
1
1/10/2020 7:46:20 PM

Popular Answer

You want to assign All the Items ins your model, to just one Entity in another table? This is a design error.

Also I'm not sure you can replace an entire collection in one entity. You have to clear them and add new items. You are assigning a DbSet to existing. Items, that's definitely impossible.

Edit Another thing: You create a new Context for 'existing' and you attach something from an other source. Maybe your Items come from another context. They need to be attached to this dc context.



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow