【发布时间】:2019-05-21 14:41:13
【问题描述】:
我在使用 EF Core 2.2.3 更新 .Net Core 2.2.0 中的实体时遇到问题。
保存更改时出错。错误详情: 无法跟踪实体类型“资产”的实例,因为已经在跟踪具有相同键值 {'Id'} 的另一个实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用
DB Context 是这样注册的:
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 的所有条目的状态。然后它起作用了..但它没有任何意义,至少就我目前的知识而言..
我找到了this question,但没有有效的答案,只有关于 EF 如何进行跟踪的变通方法和假设。
更新 这是一个指向 bitbucket 的链接,其中包含重现此问题的示例:EF Core Update Sample
我序列化了从上下文中检索到的对象。
【问题讨论】:
-
每个请求有超过 1 个上下文实例。正如你所提到的。使用 Detach 不是一个有效的解决方案,您需要找到根本原因。你如何注入 _context 类型?
-
“它在此交易之前包含一些检查,但在此上下文中没有足够的相关性。” 你确定吗?
_context.Set<Asset>().Local.Count == 0在调用_context.Anomalies.Update(anomaly);之前是真的吗? -
@Ivan,看来
_context.Set<Asset>().Local.Count == 0是false。我最终在检查之前评论了所有代码,但它仍然是错误的.. -
@ilkerkaran,我在构造函数中注入
_context,如下所示:public AnomalyManager(SAMSDbContext context){_context = context;}其中_context是private readonly字段。在最初的问题中,我发布了 DbContext 如何在Startup.cs中注册
标签: c# entity-framework asp.net-core .net-core entity-framework-core