【问题标题】:In Entity Framework, what is the difference between Add and Attach and how can I solve my problem?在 Entity Framework 中,Add 和 Attach 有什么区别,我该如何解决我的问题?
【发布时间】:2011-04-20 07:34:23
【问题描述】:

我最近开始使用实体框架,检查我是否真的需要向数据库添加新记录有点痛苦。

如果我需要添加到数据库的 Entity 已经在它上面,我会知道,因为我在插入它之前会进行查询,如果它存在,那么我会保留该实例,因为我需要在某些关系中使用它。

假设我的实体名称是Book

当一个实体不在数据库中时,问题就出现了,我这样做了:

Book b = //...
modelContainer.AddToBooks(b);

我可以轻松做到:

modelContainer.SaveChanges()

每次我添加一个新实体(无论它是什么实体),这都会正常工作,因为我一次插入一种条目,并检查它是否已经在数据库中,我赢了'没有重复问题。

但如果我想避免如此频繁地拨打SaveChanges() 怎么办?

在这个问题中:Is is possible to check if an object is already attached to a data context in Entity Framework?,问题的作者提供了一种在我的情况下对我有帮助的方法,但是如果我将Add 对象指向上下文而不是Attaching 它,则它不起作用。

我的问题(可能是两个,但非常相关)是:Add 和 Attach 有什么区别以及如何解决我的问题?

编辑:
这是我遇到的问题的一个示例。

我有一个实体 Result,它与另外两个实体有关系:TrainerHorse

我从外部来源获取数据,因此我必须手动创建所有实体。

每次我需要插入一个新的Trainer,我都会这样做:

var trainer = Trainer.CreateTrainer(Id)

然后我查询数据库以查看具有Id 的培训师是否已经在数据库中。如果是,那么我将trainer 变量替换为数据库中的变量。

如果不是,我可以在这里做两件事:

  • 将训练器附加到上下文(我可以使用密钥检查它是否已经存在)
  • 将培训师添加到上下文中(使用AddToTrainers(...)

Horse 的过程相同。

现在,当我需要创建一个新的 Result(其中包含一个 Trainer 和一个 Horse)时,我将之前的训练器和马分配给该结果实例。

我应该在这里做什么才能将新的Result 添加到上下文中?

  • 如果我附加训练器/马,那么当我附加结果时,我会收到 InvalidOperationException,告诉我训练器已经在对象上下文中。
  • 如果我添加培训师而不是附加培训师,我会收到另一个错误(现在不记得了,但它告诉我培训师已经在数据库中)。

重要提示:
附加结果时出现第一个错误,执行SaveChanges()时出现第二个错误。

我在这里要避免的是每次添加新结果时都调用SaveChanges()

【问题讨论】:

    标签: c# entity-framework


    【解决方案1】:

    ObjectContext 在内部跟踪所有由上下文加载、附加或添加的实体。调用SaveChanges 时,只能在数据库中修改这些实体。每个这样的实体在ObjectStateManager 中都有一个ObjectStateEntryObjectStateEntry 的主要属性之一是State。状态是枚举类型EntityState,它提供以下值:

    • 已添加
    • 已删除
    • 分离
    • 修改
    • 不变

    从数据库加载的每个实体都处于Unchanged 状态。分离是一种特殊的状态。您不会在ObjectStateManager 中找到处于分离状态的ObjectStateEntry。但是,如果您向 ObjectStateManager 询问 ObjectStateEntry 以获取上下文未跟踪的实体,它将创建一个具有 Detached 状态的新 ObjectStateEntry

    现在AttachAddObject的区别:

    • Attach - 如果您调用此方法ObjectContext 将开始跟踪整个对象图(主要实体和所有相关实体)。所有尚未跟踪的实体都将设置为Unchanged 状态。
    • AddObject - 如果您调用此方法ObjectContext 也将开始跟踪整个对象图(主要实体和所有相关实体)。不同之处在于,尚未跟踪的所有实体都将设置为Added 状态(= 必须设置为数据库的新对象)。

    【讨论】:

    • @Ladislav 谢谢你的回答。根据我的问题,当我已经添加/附加了B 的实例时,如何避免插入与B 实例有关系的实体A 的实例?我只想插入A 的实例,但我得到InvalidOperationException
    • 在您的问题中添加示例。
    • 让我们先尝试附加/添加实体,一旦它们连接到上下文设置它们的关系。
    • @Ladislav 嗯.. 有趣...我将尝试将 result 添加到上下文中,然后设置与 trainerhorse 的关系,两者都已经在上下文中或在数据库。你是这个意思吗?
    • @Ladislav 我对这个问题和你的答案都投了赞成票。很好的解释。现在 Attach 和 Add 之间的区别很明显了。我没有更频繁地看到 Attach 的任何用法,因为在加载实体时,我们将使用 ObjectContext 来加载它,这会将 State 设置为 Unchanged,因此它永远不会被 Detached。你能描述一下Attach函数的用法吗
    【解决方案2】:

    我知道我写这篇文章有点晚了,但一直在寻找类似的解决方案......然后我发现这篇 Microsoft 文章可能简洁地回答了 OP 的大部分问题,并且可能对未来的 SO 观众有所帮助?:

    Add/Attach and Entity States == (http://msdn.microsoft.com/en-us/data/jj592676.aspx)

    来自文章:

    本主题将介绍如何将实体添加和附加到上下文以及实体框架如何在 SaveChanges 期间处理这些。

    具体请看该页面的最后一部分:

    插入或更新模式:某些应用程序的常见模式是将实体添加为新实体(导致数据库插入)或将实体附加为现有实体并将其标记为已修改(导致数据库更新)取决于主键的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-12
      相关资源
      最近更新 更多