Entity Framework Core Обновить проблему дочерних объектов - PullRequest
0 голосов
/ 08 октября 2019

В моем ASP.NET Core 2.2. Проект MVC У меня есть форма master-detail, которую я использую для редактирования таблицы PARENT, в которой также есть список дочерних объектов (хранится в таблице CHILD).

Когда я сохраняю изменения в форме, я сначала сохраняю изменения в родительской сущности, а затем запускаю следующий метод для обновления соответствующих дочерних сущностей:

private void UpdateChildList(ParentModel model)
{
    // lists
    var listOld = _parents.Get(model.IdParent).ListChilds;
    var listNew = model.ListChilds;
    var listNewInt = from x in listNew select x.IdChild;

    // 1. remove deleted
    var deleteList = new List<int>();
    deleteList = listOld.Where(t => !listNewInt.Contains(t.IdChild)).Select(x => x.IdChild).ToList();

    foreach (var d in deleteList)
    {
        var item = listOld.Where(x => x.IdChild == l).First();
        _parents.DeleteChild(item);
    }

    // 2. update existing
    var list = from x in listNew
    where x.IdChild > 0
    select x;

    foreach (var item in list)
    {
        _parents.UpdateChild(item);
    }

    // 3. add new 
    list = from x in listNew
    where x.IdChild == 0
    select x;

    foreach (var item in list)
    {
        _parents.AddChild(item);
    }
}

1. удаление работает нормально, а 3. добавление работает нормально, но 2. ОБНОВЛЕНИЕ приводит к следующей ошибке:

InvalidOperationException: Экземпляр типа сущности«Дочерний» не может быть отслежен, потому что другой экземпляр с тем же значением ключа для {'IdChild'} уже отслеживается. При подключении существующих объектов убедитесь, что подключен только один экземпляр объекта с данным значением ключа. Подумайте об использовании DbContextOptionsBuilder.EnableSensitiveDataLogging для просмотра конфликтующих значений ключей.

Примечание: я использую service.AddScoped для добавления служб в мой класс запуска.

EDIT: I 'm добавление кода из моего HTTPPost (в контроллере):

[HttpPost]
public IActionResult Edit(ParentModel model)
{
    // valid check
    if (!ModelState.IsValid)
    {
        /// ... some lists for dropdowns here

        return View(model);
    }

    var item = _parents.Get(model.IdParent);

    item.Field1 = model.Field1;
    // ... and other fields

    // update parent
    _parents.Update(item);

    // update Child list
    UpdateChildList(model);

    return RedirectToAction("Index");

}

EDIT2: добавление моего кода для удаления / обновления / добавления дочерних записей

public void AddChild(Child item)
{
    _dbContext.Add(item);
    _dbContext.SaveChanges();
}

public void UpdateChild(Child item)
{
    _dbContext.Update(item);
    _dbContext.SaveChanges();
}

public void DeleteChild(Child item)
{
   _dbContext.Remove(item);
   _dbContext.SaveChanges();
}

1 Ответ

1 голос
/ 09 октября 2019

Когда вы делаете:

var listOld = _parents.Get(model.IdParent).ListChilds;

Entity Framework извлекает информацию из контекста и начинает отслеживать эту сущность, а когда вы делаете:

_parents.UpdateChild(item);

, вы вызываете:

_dbContext.Update(item);

Который на другой стороне пытается снова присоединить эту сущность к контексту и устанавливает для EntityState значение Modified, и поэтому вы получаете исключение.

Когда вы извлекаете информацию из базы данных и затем работаетес ним вы находитесь в так называемом «подключенном сценарии», и контекст Entity Framework отслеживает все найденные объекты. Как только вы изменяете некоторые данные этих объектов, контекст устанавливает их EntityState в Modified, потому что выполняется модификация. Итак, вы можете вызвать метод SaveChanges(), он создает и выполняет оператор Update в базе данных.

Таким образом, у вас есть две опции:

  1. Add .AsNoTracking()в вашем поисковом запросе, поэтому вы не будете отслеживать запросы и никакие сущности не будут добавлены в контекст db соответственно. Затем вы будете работать в «Отключенном сценарии» и можете использовать метод db context Update();

  2. Измените метод UpdateChild, сопоставив поле с полем, чтобы изменить поле в сущности. установит EntityState на Modified. Затем вообще удалите _dbContext.Update(item), потому что SaveChanges() сделает всю работу.

Еще одна вещь, которую стоит упомянуть - выполнение SaveChanges() в цикле, как правило, не очень хорошая идея. Это означает, что вы отправляете (n) запросов в базу данных, где (n) - количество записей.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...