我们有一个最初运行在EFCore 2.2.6和.Net Core2.1上的应用程序。我们有下面的代码来查询和删除数据,它使用AsNoTracking:
var deletedDiag = _unitOfWork.GetRepository<DIAGNOSIS_DETAIL>()
.GetAll(c => c.Diag.CMS_CASE_ID == model.DiagnosisModel.CASE_ID)
.Include(i => i.Diag).AsNoTracking().ToList();
if (deletedDiag != null)
{
foreach (var del in deletedDiag)
{
if (!model.SUBDETAILS.Any(a => a.DIAGNOSIS_DETAIL_ID == del.DIAGNOSIS_DETAIL_ID))
{
_unitOfWork.GetRepository<DIAGNOSIS_DETAIL>().Delete(del);
}
}
}删除以下内容:
public void Delete(TEntity entity) => _dbSet.Remove(entity);deletedDiag查询有一个包含作为导航属性引入Diag,在此代码块之上,另一个查询获取相同的Diag并标记它以进行更新。
在EFCore 2.2.6中,delete工作正常,它能够更新Diag,然后运行delete,即使deletedDiag有一个路径,也没有错误。在EFCore 5.0.8中,我们得到一个错误,说明当我们尝试删除时,实体已经被跟踪,修复方法是让deletedDiag停止跟踪它,但是将它设置为null:
deletedDiag.ForEach(x => x.Diag = null);这是可行的,但为什么它在2.2.6中有效呢?
发布于 2021-08-27 21:34:35
这是由于EF从一开始就在许多特性和默认情况下采取的反复无常的路径。不可能跟踪不同版本之间的所有更改,尽管它们都有很好的文档记录。
v3的变化之一是在无跟踪行为地区。在EF-core 2中,AsNoTracking执行标识解析,它确保结果集中具有给定键的所有实体的出现都由同一个实体实例表示。在EF-core 3中,这被放弃了:“相同”实体的每一次出现现在都是一个新的实例。
这意味着在EF 2中,_dbSet.Remove(entity)语句重复标记相同的Diag实例:即在未附加时附加它,并将其状态设置为Deleted。这不是问题。
EF-core 3+试图使用相同的键附加不同的Diag实例,但失败。
幸运的是,在EF核心5中,可以使用AsNoTrackingWithIdentityResolution恢复早期的跟踪行为。
var deletedDiag = _unitOfWork.GetRepository<DIAGNOSIS_DETAIL>()
.GetAll(c => c.Diag.CMS_CASE_ID == model.DiagnosisModel.CASE_ID)
.Include(i => i.Diag)
.AsNoTrackingWithIdentityResolution()
.ToList();https://stackoverflow.com/questions/68958877
复制相似问题