【问题标题】:Entity Framework Core. How to update the related data properly?实体框架核心。如何正确更新相关数据?
【发布时间】:2019-06-10 08:29:26
【问题描述】:

这个问题很常见,但我还是不明白如何正确更新相关实体?

我有以下代码:

    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 确实如此:优先级正在改变。当我尝试仅调用 Update 时,EF 会尝试插入新步骤而不是更新现有步骤。

那么,你能告诉我,这里最好的做法是什么?

提前非常感谢!

【问题讨论】:

  • 您想要 (1) 更新 Step 实体或 (2) 仅更新 StepLevelStep 导航属性?虽然(2)在您使用StepId == step.Id 检索StepLevel 时没有意义。
  • 我想同时更新 Step(一些字段,例如 Name)和 StepLevel(优先级)实体。

标签: c# sql-update entity-framework-core one-to-many


【解决方案1】:

首先,分离实体不会分离相关实体,因此分离item不会分离使用.Include(sl =&gt; sl.Step)检索到的item.Step

其次,由于您不想更改item.Step,而是要更新现有的Step实体(x.StepId == step.Id),并且您知道上下文正在跟踪(包含)对应的Step实体从数据库加载,您应该使用通过Entry(...).CurrentValues.SetValues 方法从分离实体更新数据库实体的过程。

所以删除

item.Step = step;

并改用以下内容:

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

最后一点。当您使用附加实体时,不需要(不应该)使用Update 方法。如果有任何实体被跟踪,更改跟踪器将自动检测更改的属性值。

【讨论】:

  • 它有帮助!非常感谢!
【解决方案2】:

上下文正在跟踪从数据库加载的相应 Step 实体,因此它会引发此错误。您可以更新每个 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;
            }

        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-04
    • 2020-07-19
    • 1970-01-01
    • 1970-01-01
    • 2021-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多