Entity Framework核心。如何正确更新相关数据?
Entity Framework Core. How to update the related data properly?
这个问题很常见,但我还是不明白如何正确更新相关实体?
我有以下代码:
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.
据我所知,自从方法开始时的 select 请求以来,实体正在被跟踪。好的,但是当我分离实体并调用 Update 方法(参见注释行)时,Step 实体没有被更改。但 StepLevel 确实如此:优先级正在改变。当我尝试仅调用 Update 时,EF 会尝试插入新步骤而不是更新现有步骤。
那么,你能给我一些建议吗,这里最好的练习是什么?
提前致谢!
首先,分离实体不会分离相关实体,因此分离 item
不会分离使用 .Include(sl => 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
方法。如果任何实体被跟踪,更改跟踪器将自动检测更改的 属性 值。
上下文正在跟踪从数据库加载的相应步骤实体,因此它抛出此错误。您可以更新每个步骤 属性 -
public bool UpdateStepAssignedToLevelAsync(Step step, int levelId)
{
using(var context = new WhosebugDbContext())
{
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;
}
}
这个问题很常见,但我还是不明白如何正确更新相关实体?
我有以下代码:
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.
据我所知,自从方法开始时的 select 请求以来,实体正在被跟踪。好的,但是当我分离实体并调用 Update 方法(参见注释行)时,Step 实体没有被更改。但 StepLevel 确实如此:优先级正在改变。当我尝试仅调用 Update 时,EF 会尝试插入新步骤而不是更新现有步骤。
那么,你能给我一些建议吗,这里最好的练习是什么?
提前致谢!
首先,分离实体不会分离相关实体,因此分离 item
不会分离使用 .Include(sl => 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
方法。如果任何实体被跟踪,更改跟踪器将自动检测更改的 属性 值。
上下文正在跟踪从数据库加载的相应步骤实体,因此它抛出此错误。您可以更新每个步骤 属性 -
public bool UpdateStepAssignedToLevelAsync(Step step, int levelId)
{
using(var context = new WhosebugDbContext())
{
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;
}
}