Entity Framework Core не будет обновлять ICollection - PullRequest
1 голос
/ 10 января 2020

Попытка выполнить обновление объекта с вложенным списком. Я продолжаю получать эту ошибку независимо от того, что я делаю. Я пробовал это: Обновление вложенных объектов в Entity Framework и это: Обновление вложенных объектов в платформе сущностей

Ожидается, что операция базы данных повлияет на 1 строку ) но на самом деле затронуло 0 строк. Данные могут быть изменены или удалены с момента загрузки объектов. См. http://go.microsoft.com/fwlink/?LinkId=527962 для получения информации о понимании и обработке оптимистических c исключений параллелизма.

"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 ]

2 голосов
/ 10 января 2020

Вы хотите назначить все элементы вашей модели только одному объекту в другой таблице? Это ошибка дизайна.

Также я не уверен, что вы можете заменить всю коллекцию в одном объекте. Вы должны очистить их и добавить новые предметы. Вы присваиваете DbSet существующим. Предметы, это определенно невозможно.

Редактировать Другое дело: вы создаете новый контекст для «существующего» и присоединяете что-то из другого источника. Может быть, ваши Items происходят из другого контекста. Они должны быть присоединены к этому dc контексту.

1 голос
/ 10 января 2020

У меня сложилось впечатление, что, поскольку вы вызываете функцию _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;
1 голос
/ 10 января 2020

Это длинный выстрел, я не несу ответственности, если ваш P C взрывается, попробуйте это:

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