实体框架代码优先 - DbContext 上没有 Detach() 方法

Posted

技术标签:

【中文标题】实体框架代码优先 - DbContext 上没有 Detach() 方法【英文标题】:Entity Framework Code First - No Detach() method on DbContext 【发布时间】:2011-05-09 06:13:00 【问题描述】:

我想知道为什么 DbContext 对象上没有像 ObjectContext 那样的 Detach 方法。我只能假设这种遗漏是故意的,但我很难弄清楚为什么。我需要能够分离和重新附加实体(例如,用于将缓存放入 ASP.NET 项目中)。但是,由于我无法分离实体,所以当我尝试附加与先前上下文关联的实体时,我得到“一个实体对象不能被多个 IEntityChangeTracker 实例引用”异常。

这里的指导是什么?我错过了什么吗?

【问题讨论】:

有什么要说的:“这里的指导是什么?我错过了什么吗?”就个人而言,我只对在寻找从上下文中读取实体的解决方案时使用 Detach 感兴趣,就在保存从 UI 返回的实例之前。这给了我“ObjectStateManager 中已经存在具有相同键的对象。ObjectStateManager 无法跟踪具有相同键的多个对象。” 【参考方案1】:

对于可能偶然发现这个问题的人,从 CTP5 开始,您现在需要编写

((IObjectContextAdapter)context).ObjectContext

为了到达 ObjectContext。

【讨论】:

+1 干净、优雅、一个衬里。我喜欢它。还想指出,该接口专门在这里找到:System.Data.Entity.Infrastructure.IObjectContextAdapter,是的,就像 Pandincus 指出的那样,您也必须引用 System.Data.Entity。【参考方案2】:

DbContext 在内部使用 ObjectContext,EF 团队将其作为 protected 属性提供,以防万一您需要下拉到较低级别的 API,听起来就是这种情况,所以您可以从派生的 DbContext 使用或公开所需的功能:

public class YourContext : DbContext 

    public void Detach(object entity) 
    
        ObjectContext.Detach(entity);            
    

然后你可以从你的控制器调用这个方法来分离一个实体。

或者,您可以将其更改为拥有更丰富的 API:

public class YourContext : DbContext

    public void ChangeObjectState(object entity, EntityState entityState)
    
        ObjectContext.ObjectStateManager.ChangeObjectState(entity, entityState);
    

以下是元数据中 DbContext 的样子:

public class DbContext : IDisposable 
      
    protected System.Data.Objects.ObjectContext ObjectContext  get; 
    ...

【讨论】:

@Stacker 这不是答案,因为它需要上面所选答案中概述的演员表,即DbContext 实现IObjectContextAdapter 给它ObjectContext 属性,否则无法访问。结合 2 个答案在下面给出@splite 的答案 ChangeObjectState 非常懒惰,它使用“带演员阵容的线性算法”......有点......你知道......非常糟糕。【参考方案3】:

EF:CF 4.1 RC1EF:CF 4.1 RTW 具有相同的显式实现的 IObjectContextAdapter:

public static class DbContextExtensions

    public static void Detach(this System.Data.Entity.DbContext context, object entity)
    
         ((System.Data.Entity.Infrastructure.IObjectContextAdapter)context).ObjectContext.Detach(entity);
    

微软认为“分离技术太先进,应该隐藏”。恕我直言,发明这个的人应该被枪杀——因为如果你添加全新的实体,否则很难在不对 db 进行更改的情况下将其删除(你可以使用 DbEntityEntry 进行操作,但那是另一回事了)。

4 年后编辑:

使用 EF6(我不知何故跳过了 EF5 :))您不再需要 detach(),因为删除新添加的条目不会像在 EF4 中那样生成 delete from [table] where [Id] = 0 - 您只需调用 mySet.Remove(myFreshlyCreatedAndAddedEntity)一切都会好起来的。

【讨论】:

开枪了吗?反正谁需要这个功能? :P @quetzalcoatl : var context = ...; var poco = new Poco(); context.Add(poco); context.Remove(poco); (5 min for edit gone, sry :) ) 当时我很生气...当你在制作 windows 应用程序时,你必须有一些方法来“取消创建新的,可能不完整条目但保留 UoW 上下文”......我们摆脱了整个 EF 顺便说一句,并编写我们自己的 ORM:没有办法利用延迟加载(我有一堆发票,我无法在单个“发票 ID 所在的位置”中加载每个 InvoiceItem( xxyy)" 查询 - 包括不按我们预期的方式工作),更大的存储库非常懒惰(在每次执行之前进行线性(!!!)搜索,wtf ...),为 100 多种 poco 类型创建代理需要太多时间,所以在... 最后顺便说一句,我说的是用于生产的大型(= 5 名程序员全职工作 2 年)应用程序(= 媒体中的人们会用它赚钱),其中 fast(和丰富多彩的:)))应用程序是好应用程序。我们必须“弯曲”一些东西以使其超快...具有 1k+ 条目的组合框(在特定的而非通用的情况下,您可以或不能 CRUD 条目)角色管理?必须在0.2s以下...如果你写ASP或小应用程序,它不会那么痛苦;) Heyheyhey.. 我在开玩笑,注意最后的 ':P' :) 似乎我不小心骗到了你,对不起 :) 我完全同意你的看法。没有真正的附加/分离支持使得框架对于任何重要的用途都非常有限,这就是为什么它们被引入到较新版本的 EF 中。从你给出的数字来看,这听起来像是一个“中等”项目和数据库,并不是真正的庞大,但这是非常主观的,我不知道你的项目。无论如何,根据我的经验,大多数 ORM/DB 问题不是来自 ORM,而是来自定义不明确的业务逻辑,或者来自不是为通过 ORM 使用而设计的 DB。【参考方案4】:

我通常使用以下属性扩展基类(从 DbContext 继承):

public class MyDbContext : DbContext

    public ObjectContext ThisObjectContext
    
        get
        
            return ((IObjectContextAdapter)this).ObjectContext;
        
    

稍后您可以将此属性用于各种有用的东西...例如分离 :)

【讨论】:

以上是关于实体框架代码优先 - DbContext 上没有 Detach() 方法的主要内容,如果未能解决你的问题,请参考以下文章

如何从DbContext中清除未插入的POCO? - 实体框架代码优先

无法使用 DbContext 实体框架核心 SaveChanges()

orm 实体框架 4 和代码优先

在 DbContext 中看不到实体框架数据库更改

将连接字符串传递给代码优先的 DbContext

将实体框架从数据库优先转换为代码优先