EF Core“另一个实例已被跟踪”

编程入门 行业动态 更新时间:2024-10-26 14:39:01
本文介绍了EF Core“另一个实例已被跟踪”的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我在使用EF Core 2.2.3更新.Net Core 2.2.0中的实体时遇到问题。

保存更改时发生错误。错误详细信息:无法跟踪实体类型 Asset的实例,因为已经跟踪了另一个具有相同 {'Id}关键字值的实例。附加现有实体时,请确保仅附加一个具有给定键值的实体实例。考虑使用

这是注册数据库上下文的方式:

服务.AddDbContext(options =>

options.UseSqlServer(Configuration.GetConnectionString( DbConnection)),ServiceLifetime.Scoped);。

已设置作用域的生存期默认情况下,但我写起来更容易理解。

已获得 Anomaly 对象像这样:

public IQueryable< Anomaly> GetAll() {返回_context.Anomalies.Include(a => a.Asset).Include(a => a.Level)} 公共异步任务;异常> GetAnomaly(int anomalyId,用户) { var anomaly = await GetAll() .FirstOrDefaultAsync(a => a.Id == anomalyId); 返回异常; }

和 Update()方法如下:

使用(var transaction = _context.Database.BeginTransaction()) { try { _context.Anomalies.Update(anomaly); _context.SaveChanges(); transaction.Commit(); } catch(例外) { transaction.Rollback(); 投掷; } }

此交易前包含一些支票,但在这种情况下没有足够的相关性。

这是我收到的错误,因为实例已被跟踪。我不明白这是怎么发生的..如果上下文是 Scoped ,则

...在这种情况下,将为每个请求创建一个新的服务实例

如果我在PUT请求上的上下文与GET请求的上下文不同,那么如何跟踪实体?

使其工作的唯一方法是设置 ChangeTracker 到 EntityState.Detached 。然后它起作用了..但这至少没有意义,至少就我目前所知。。

我发现

解决方案

默认情况下,当您检索被跟踪的实体时,由于已跟踪它们,因此您可以仅调用SaveChanges而不调用Update。您还可以通过使用.AsNoTracking()

检索实体而不跟踪它们,如果尚未跟踪,则需要更新,因此,如果您使用AsNoTracking,那么您确实需要使用Update在SaveChanges之前

public IQueryable< Anomaly> GetAll() {return _context.Anomalies .Include(a => a.Asset) .Include(a => a.Level); } 公共异步任务<异常> GetAnomaly(int anomalyId,用户) { var anomaly =等待GetAll() .AsNoTracking() .FirstOrDefaultAsync(a => a.Id == anomalyId) ; 返回异常; }

您还可以检查是否跟踪该实体以知道是否调用Update或不是:

使用(var transaction = _context.Database.BeginTransaction()) { try { 布尔跟踪= _context.ChangeTracker.Entries< Anomaly>()。Any(x => x.Entity.Id == anomaly.Id); if(!tracking) { _context.Anomalies.Update(anomaly); } _context.SaveChanges(); transaction.Commit(); } catch(例外) { transaction.Rollback(); 投掷; } }

I have a problem updating an entity in .Net Core 2.2.0 using EF Core 2.2.3.

An error occurred while saving changes. Error details: The instance of entity type 'Asset' cannot be tracked because another instance with the same key value for {'Id'} is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached. Consider using

This is how the DB Context is registered:

services.AddDbContext(options =>

options.UseSqlServer(Configuration.GetConnectionString("DbConnection")), ServiceLifetime.Scoped);

The Scoped lifetime is set by default but I wrote it to be more easy to understand.

The Anomaly object is got like this:

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; }

And the Update() method looks like this:

using (var transaction = _context.Database.BeginTransaction()) { try { _context.Anomalies.Update(anomaly); _context.SaveChanges(); transaction.Commit(); } catch (Exception ex) { transaction.Rollback(); throw; } }

It contains some checks before this transaction, but none relevant enough in this context.

This is where I get the error with instance already being tracked. I can't understand how this happens .. If the context is Scoped, then

... "a new instance of the service will be created for each scope", in this case, for each request

If my context on the PUT request is different from the context of the GET request, how is the entity already being tracked? How does this work at the most basic levels?

The only way to make it work is to set the state for all entries from the ChangeTracker to EntityState.Detached. Then it works.. but it makes no sense, at least to my current knowledge..

I found this question but with no valid answer, only with workarounds and assumptions about how EF does the tracking.

UPDATE Here is a link to bitbucket with a sample recreating this problem: EF Core Update Sample

I serialized the objects retrieved from the context.

With Tracking on the LEFT <====> With NO tracking on the RIGHT

解决方案

By default when you retrieve entities they are tracked and since they are tracked you could just call SaveChanges and not call Update. You can also retrieve entities without tracking them by using .AsNoTracking()

calling Update is needed if not tracked already, so if you use AsNoTracking then you do need to use Update before SaveChanges

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; }

You can also check if the entity is tracked to know whether to call Update or not:

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; } }

更多推荐

EF Core“另一个实例已被跟踪”

本文发布于:2023-11-13 23:39:51,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1585626.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:已被   实例   EF   Core

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!