Entity Framework Core.Как правильно обновить связанные данные? - PullRequest
0 голосов
/ 30 ноября 2018

Этот вопрос является распространенным, но я все еще не могу понять, как правильно обновить связанный объект?

У меня есть следующий код:

    public async Task<bool> UpdateStepAssignedToLevelAsync(Step step, Guid levelId, int priority = -1)
    {
        var item = await this._context.StepLevels
            .Include(sl => sl.Step)
            .FirstOrDefaultAsync(x => x.StepId == step.Id && x.LevelId == levelId);
        if (item == null)
        {
            return false;
        }

        //this._context.Entry(item).State = EntityState.Detached;
        if (priority > -1)
        {
            item.Priority = priority;
        }

        item.Step = step;

        //this._context.StepLevels.Update(item);
        var rows = await this._context.SaveChangesAsync();
        return rows > 0;
    }

Когда он запускается, яполучаю следующую ошибку:

InvalidOperationException: The instance of entity type 'Step' cannot be tracked because another instance with the key value '{Id: 35290c18-5b0a-46a5-8f59-8888cf548df5}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

Как я понимаю, сущность отслеживается с момента запроса выбора в начале метода.Хорошо, но когда я отсоединяю сущность и вызываю метод Update (см. Закомментированные строки), сущность Step не изменяется.Но StepLevel делает: приоритет меняется.Когда я пытаюсь вызвать просто Обновить, EF пытается вставить новый Шаг вместо обновления существующего.

Итак, не могли бы вы посоветовать мне, что лучше всего использовать здесь?

Заранее большое спасибо!

Ответы [ 2 ]

0 голосов
/ 10 июня 2019

Контекст отслеживает соответствующий объект Step, загруженный из БД, по этой причине он выдает эту ошибку.Вы можете обновить каждое свойство шага -

public bool UpdateStepAssignedToLevelAsync(Step step, int levelId)
        {
            using(var context = new StackOverFlowDbContext())
            {
                var item = context.StepLevels
                                  .Include(sl => sl.Step)
                                  .FirstOrDefault(x => x.Id == step.Id && x.Id == levelId);
                if (item == null)
                {
                    return false;
                }

                // Updating Name property
                item.Step.Name = step.Name;

                // Other properties can be upadated

                var rows = context.SaveChanges();
                return rows > 0;
            }

        }
0 голосов
/ 30 ноября 2018

Во-первых, отсоединение сущности не отсоединяет связанные сущности, поэтому отсоединение item не отсоединяет item.Step, полученный с помощью .Include(sl => sl.Step).

Во-вторых, поскольку вы не хотите изменять item.Step, но чтобы обновить существующую сущность Step (x.StepId == step.Id), и вы знаете, что контекст отслеживает (содержит) соответствующую сущность Step, загруженную из базы данных, следует использовать процедуру обновления сущности dbиз отсоединенного объекта с помощью метода Entry(...).CurrentValues.SetValues.

Поэтому удалите

item.Step = step;

и используйте вместо него следующее:

this._context.Entry(item.Step).CurrentValues.SetValues(step);

Последнее примечание.Когда вы работаете с присоединенными объектами, нет необходимости (не следует) использовать метод Update.Средство отслеживания изменений автоматически обнаружит измененные значения свойств, если какой-либо объект отслеживается.

...