c# - EF Core '另一个实例已被跟踪'
问题描述
我在使用 EF Core 2.2.3 更新 .Net Core 2.2.0 中的实体时遇到问题。
保存更改时出错。错误详细信息:无法跟踪实体类型“资产”的实例,因为已经在跟踪具有相同键值 {'Id'} 的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用
这是数据库上下文的注册方式:
services.AddDbContext(选项 =>
options.UseSqlServer(Configuration.GetConnectionString("DbConnection")), ServiceLifetime.Scoped);
生命Scoped
周期是默认设置的,但我写它是为了更容易理解。
Anomaly
对象是这样的:
public IQueryable<Anomaly> GetAll()
{return _context.Anomalies.Include(a => a.Asset).Include(a => a.Level)
}
public async Task<Anomaly> GetAnomaly(int anomalyId, User user)
{
var anomaly = await GetAll()
.FirstOrDefaultAsync(a => a.Id == anomalyId);
return anomaly;
}
该Update()
方法如下所示:
using (var transaction = _context.Database.BeginTransaction())
{
try
{
_context.Anomalies.Update(anomaly);
_context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
throw;
}
}
它包含此事务之前的一些检查,但在此上下文中没有足够的相关性。
这是我得到实例已经被跟踪的错误的地方。我不明白这是怎么发生的..如果上下文是Scoped
,那么
...“将为每个范围创建一个新的服务实例”,在这种情况下,对于每个请求
如果 PUT 请求的上下文与 GET 请求的上下文不同,那么如何跟踪实体?这在最基本的层面上是如何运作的?
使其工作的唯一方法是为从ChangeTracker
to的所有条目设置状态EntityState.Detached
。然后它起作用了..但它没有任何意义,至少以我目前的知识..
我发现了这个问题,但没有有效的答案,只有关于 EF 如何进行跟踪的变通方法和假设。
更新 这是一个指向 bitbucket 的链接,其中包含重现此问题的示例:EF Core Update Sample
我序列化了从上下文中检索到的对象。
解决方案
默认情况下,当您检索实体时,它们会被跟踪,并且由于它们被跟踪,您可以只调用 SaveChanges 而不是调用 Update。您还可以使用 .AsNoTracking() 检索实体而不跟踪它们
如果尚未跟踪,则需要调用 Update,因此如果您使用 AsNoTracking 那么您确实需要在 SaveChanges 之前使用 Update
public IQueryable<Anomaly> GetAll()
{ return _context.Anomalies
.Include(a => a.Asset)
.Include(a => a.Level);
}
public async Task<Anomaly> GetAnomaly(int anomalyId, User user)
{
var anomaly = await GetAll()
.AsNoTracking()
.FirstOrDefaultAsync(a => a.Id == anomalyId);
return anomaly;
}
您还可以检查是否跟踪实体以了解是否调用更新:
using (var transaction = _context.Database.BeginTransaction())
{
try
{
bool tracking = _context.ChangeTracker.Entries<Anomaly>().Any(x => x.Entity.Id == anomaly.Id);
if (!tracking)
{
_context.Anomalies.Update(anomaly);
}
_context.SaveChanges();
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
throw;
}
}
推荐阅读
- spring - SFTP 适配器正在跳过备用文件
- flutter - Flutter firebase - 获取多对多关系表
- sql - Spark SQL 组,map reduce
- linux - awk - 拉出对列并获取出现次数
- bash - 如何从 100 个文件中求和 - bash/awk?
- schema - 如何解决“审查是针对不支持类型的事物类型的项目。”
- c - 为什么简单的程序会占用这么多存储空间?
- loops - 如何在 rust 中遍历字典对象?
- jupyter-notebook - 如何将 Jupyter Notebook 中的“chesterish”主题导入 JupyterLab?
- c# - 以字符串形式获取过去 7 天