ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Entity Framework Code First 中分离对象?

DbContext 上没有 Detach(object entity)

我是否有能力先分离 EF 代码上的对象?


S
Slauma

这是一个选项:

dbContext.Entry(entity).State = EntityState.Detached;

检索返回 IQueryable 的对象时,我可以这样做吗?
@Lol 编码器:我不确定我是否理解正确,但 entity 必须是属于您的模型类(Person、Customer、Order 等)的类型的物化对象。您不能直接传入 IQueryable<T>进入dbContext.Entry(...)。你说的是这个问题吗?
@EladBenda:这取决于。如果要分离已附加到上下文的对象,请将状态设置为 Detached。如果您想从数据库加载实体而不将它们附加到上下文(无更改跟踪),请使用 AsNoTracking
@kjbartel:这是预期的行为,因为实体与上下文没有链接。
@rcdmk 如果您在另一个答案中获得带有 AsNoTracking 的实体,则延迟加载仍然有效。这种方法不会。
s
saluce

如果您想分离现有对象,请遵循@Slauma 的建议。如果要加载对象而不跟踪更改,请使用:

var data = context.MyEntities.AsNoTracking().Where(...).ToList();

正如评论中提到的,这不会完全分离实体。它们仍然是附加的并且延迟加载工作,但实体没有被跟踪。例如,如果您只想加载实体以读取数据并且不打算修改它们,则应使用此选项。


@Ladislav:这确实可能是 Lol 编码器的意思。尽管我经常加载对象列表并立即处理上下文,但我从未使用和考虑过这种方法,例如 using(ctx){ return ctx....ToList(); }。在这种情况下,使用 AsNoTracking() 会很有意义,因为我会避免不必要地填充对象上下文。我想它可能会有性能和内存消耗的好处,尤其是对于大型列表,对吧?
@Slauma:是的,它具有性能优势。这实际上就是这种方法存在的原因。在 ObjectContext API 中使用这种方法稍微复杂一些。
这会禁用延迟加载吗?
实际上这不会禁用延迟加载它只会禁用更改跟踪并提高性能=实体仍然附加。我在回答这个问题后找到了它,所以你应该将@Slauma 的问题标记为有效答案。
这就是我要的。我想要延迟加载和只修改分离实体的能力。
T
The Fabio

前面的两个答案都提供了很好的说明,但是,两者都可能让您仍然将实体加载到 EF 的上下文和/或其更改跟踪器中。

当您更改小型数据集时,这不是问题,但在更改大型数据集时会成为问题。 EF 会增加内存和资源的使用,这反过来会降低过程性能,因为它使用更多的数据/实体。

其他两种方法都有效,但在这种情况下,Microsoft recommends 清理更改跟踪器而不是单独分离实体

清除数据更改循环上的更改跟踪器(例如更改一大块数据)可以让您避免这个麻烦。

context.ChangeTracker.Clear();

这将从上下文中卸载/分离所有实体及其相关的 changeTracker 引用,因此请在 context.SaveChanges() 之后小心使用。


两者都会让你的实体仍然加载到 EF 的变更跟踪器中——这不是真的。分离对象会将其从更改跟踪器中删除。如果实体是延迟加载代理,则它具有对上下文的引用,但这与附加到它不同(Ladislav 的措辞在这里有点模棱两可)。
嗨 Gert,您可以通过快速测试来验证它。实体以分离状态保留在 ChangeTracker 中。类似于内存泄漏(但不幸的是设计..)。调用 Clear 命令从上下文中删除所有实例化的实体对象
当然国家是超然的,还有什么呢?即使您创建了一个从未见过上下文的全新实体,它的状态也是分离的。这只是EF的说法:不知道这个,与它无关。另一种方法是在验证上下文之外的任何实体的状态时抛出异常。当然没有人想要那样。
然而 EF 将它保留在内存中,就像内存泄漏一样分离
感谢@TheFabio - 这解决了在 EF 中批量插入非常大的图表时的巨大性能问题。为了解决这个问题,我在保存每个实体后使用了你的线路,性能提升和内存使用提升非常棒。谢谢!