我在使用EF Core 2.2.3更新.Net Core 2.2.0中的实体时遇到了问题。
保存更改时出错。错误详情:因为存在另一个具有相同 {'Id'} 键值对的实例正在被跟踪,所以无法跟踪实体类型 'Asset' 的实例。在附加现有实体时,请确保只附加一个具有给定键值的实体实例。考虑使用
以下是DB上下文的注册方式:
services.AddDbContext(options =>
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
的条目状态设置为EntityState.Detached
。然后它可以工作...但至少根据我的当前知识,这毫无意义..
我发现这个问题,但没有有效的答案,只有关于EF如何进行跟踪的解决方法和假设。
更新 这里是一个带有重新创建此问题的示例的bitbucket链接:EF Core Update Sample
我对从上下文检索的对象进行了序列化。
_context.Set<Asset>().Local.Count == 0
是false。我最终注释掉了该检查之前的所有代码,但它仍然是false... - Marian Simonca_context
:public AnomalyManager(SAMSDbContext context){_context = context;}
其中_context
是一个private readonly
字段。在我最初发布的问题中,我提到了如何在Startup.cs
文件中注册DbContext。 - Marian Simonca