【问题标题】:Entity Framework 6 - Attaching a graph of entities queried with AsNoTracking实体框架 6 - 附加使用 AsNoTracking 查询的实体图
【发布时间】:2020-05-17 21:04:51
【问题描述】:

我正在从表 FattureFornitori 中检索实体列表,并加载它们拥有的集合(Voci,复数形式 - Voce,单数形式)以及每个 VoceTipoCosto 实体的引用:

var db = new DbGestPre();
db.Configuration.ProxyCreationEnabled = false;
var s = db.FattureFornitori
            .Include(x => x.Voci)
            .Include(x => x.Voci.Select(y => y.TipoCosto))
            .AsNoTracking().ToList();

现在,单个FattureFornitori 中的多个Voci 可以引用同一个TipoCosto。 因此,当我尝试使用其 Voci 和引用的 TipoCosto 附加单个 FattureFornitori 时,我面临以下错误:

System.InvalidOperationException: 'Attaching an entity of type 'GP.Model.TipoCosto' failed because another entity of the same type already has the same primary key value. This can happen when using the 'Attach' method or setting the state of an entity to 'Unchanged' or 'Modified' if any entities in the graph have conflicting key values. This may be because some entities are new and have not yet received database-generated key values. In this case use the 'Add' method or the 'Added' entity state to track the graph and then set the state of non-new entities to 'Unchanged' or 'Modified' as appropriate.'

对 FattureFornitori 实体(此处名为 ff)的一些调试显示:

ff.Voci[1].IdTipoCosto == ff.Voci[0].IdTipoCosto
true
ff.Voci[1].TipoCosto == ff.Voci[0].TipoCosto
false

所以 Entity Framework 为同一个实体创建了多个实例!所以 attach 方法引发的错误是有道理的。 但是这种情况怎么解决?? 我照顾了 GraphDiff 和其他类似的工具,但它们无能为力。 有什么提示吗? 谢谢!!

【问题讨论】:

  • 删除AsNoTracking()。然后 EF 将创建唯一的 TipoCosto 实例。
  • 但我不希望 EF 跟踪这些实体,也不希望它创建代理。我需要执行尽可能轻量级的操作。
  • 只是删除AsNoTracking 让生活更轻松。顺便说一句,它不需要创建代理。如果它不会对性能产生太大影响,我会选择它。

标签: .net sql-server entity-framework entity-framework-6 ef-code-first


【解决方案1】:

正如 Gert Arnold 所建议的,一种解决方法是删除 AsNoTracking()。 但这意味着数据库上下文会将所有实体添加到跟踪的实体中,因此它的性能会很差。

我尝试了以下代码:

var db = new DbGestPre();
db.Configuration.ProxyCreationEnabled = false;
db.Configuration.AutoDetectChangesEnabled = false;
var s = db.FattureFornitori
                .Include(x => x.Fornitore)
                .Include(x => x.Voci)
                .Include(x => x.Voci.Select(y => y.TipoCosto));
List<FatturaFornitore> data = s.ToList();
db.Dispose();

为了快速将实体从上下文中分离出来,我处置了上下文。欢迎任何更快/更好的方法。 此代码运行时间为 858 毫秒。

我以前的选择

var db = new DbGestPre();
db.Configuration.ProxyCreationEnabled = false;
var s = db.FattureFornitori
                .Include(x => x.Fornitore)
                .Include(x => x.Voci)
                .Include(x => x.Voci.Select(y => y.TipoCosto))
                .AsNoTracking();
List<FatturaFornitore> data = s.ToList();

只用了 500 毫秒。

所以我仍在寻找一种方法来使这个版本的代码与 AsNoTracking 一起工作。

【讨论】:

  • 很有可能因为AsNoTracking 而需要的任何重复数据删除代码将花费超过 358 毫秒。我认为AutoDetectChangesEnabled = false 的替代方案是你能得到的最好的。
  • @GertArnold 你能详细说明一下吗?我不明白你
  • 好吧,带有AsNoTracking 的代码之后需要执行重复数据删除步骤,不是吗? (* Entity Framework 为同一个实体创建多个实例!*)。我想知道这是否可以在 858-500=385 毫秒内完成。
  • 哦,好吧,我明白了! :) 是的,当然。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-01-27
  • 1970-01-01
  • 1970-01-01
  • 2016-09-07
相关资源
最近更新 更多