繁体   English   中英

在EF4.1中正确地从上下文中附加和分离实体

[英]Attaching and detaching entities from context correctly in EF4.1

我正在尝试为实体实现缓存机制。 并且为了正确无误地使用实体和缓存,我需要将实体与当前上下文分离,然后将其放入缓存中,并在从缓存中获取新上下文时将其附加回新上下文。 (我的上下文生命周期是每个http请求)

要求是 -

  1. 在分离实体时,不应删除与其关联的所有导航属性(我已经填充)。
  2. 如果我想要的话,我可以更新缓存的项目(因此正确地将它们附加到新的上下文很重要)。

这是我尝试创建一个EntityCache类 - (ServerCache这是我的包装类,它将对象推送到ASP.NET缓存)

public static class EntityCache
    {
        private static DbContext context
        {
            get
            {
                return (DbContext)HttpContext.Current.Items[ObjectKeys.ContextRequestItemKey];
            }
        }

        private static void Detach(object entity)
        {
            var trackedEntity = entity as IEntityWithChangeTracker;
            trackedEntity.SetChangeTracker(null);
            ((IObjectContextAdapter)context).ObjectContext.Detach(entity);
        }

        private static void Attach(object entity)
        {
            ((IObjectContextAdapter)context).ObjectContext.Attach((IEntityWithKey)entity);
        }

        public static void Remove(string key)
        {
            ServerCache.Remove(key);
        }

        public static object Get(string key)
        {
            object output = ServerCache.Get(key);
            if (output != null)
                Attach(output);
            return output;
        }

        public static void ShortCache(String key, object data)
        {
            if (data != null)
            {
                Detach(data);
                ServerCache.ShortCache(key, data);
            }
        }

        public static void LongCache(String key, object data)
        {
            if (data != null)
            {
                Detach(data);
                ServerCache.LongCache(key, data);
            }
        }
    }

当我在缓存中放置一个实体时,它是DynamicProxy类型而不是真正的类。

附加根本不起作用 - 我得到一个异常,我不能将类型为Dynamic_ {blahblah}的case对象转换为IEntityWithKey。

我刚看到这些在线附加和分离的例子并试过它们,我对这里的Attach / Detach方法的任何新实现持开放态度。

谢谢。

跟进问题 -

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

Works,但是使得所有加载的导航属性都为NULL,我们如何使它保持导航属性,并且当我们从上下文中分离时不用NULL替换(或丢失)它们。

IEntityWithKey是其他类型实体的接口。 它适用于“大”实体。 例如, EntityObject实现此接口。 这些实体不被视为POCO, DbContext API不支持这些实体。

如果你想使用IEntityWithKey你的类必须实现它 - 它不会自动发生。

使用DbContext API正确附加应该是:

dbContext.Set(typeof(entity)).Attach(entity); 

这应该也有效:

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

使用DbContext API正确分离应该是:

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

另外,通用方法而不是object更好。

至于你的后续问题:

...当我们从上下文中分离时,我们如何使它保持导航属性并且不用NULL替换(或丢失)它们...

我相信在保持对象图的导航属性的同时,不可能从上下文中分离对象图。 来自MSDN

在独立关联中,不为分离的对象维护关系信息。

虽然此声明与独立关联有关,但并不意味着在外键关联中维护导航属性(在模型中公开外键属性的关系)。 是,保持“关系信息”,因为外键属性(标量属性)将处于活动状态并在分离后包含正确的外键值。 但对于引用属性,相应的导航属性仍为null ,或者对于导航集合,将从集合中删除引用。

我认为从上下文中分离完整对象图的唯一方法是在完全分离原始图之前完全处理上下文或创建图的副本。 创建一个副本需要写Clone方法,其复制所有的属性和导航通过图形或使用“绝招”像这样其序列化图形转换为二进制流,然后反序列化回新对象。 为此,实体需要是可序列化的。 此外,引用周期(我们在实体之间使用双向导航属性时经常会出现这种情况)可能会带来麻烦。 (如果您的对象是包含对EF内部对象的引用并且您可能不想复制,序列化和反序列化的代理,请注意。)

在这方面, Detach不是Attach的对应物,因为它的行为完全不同: Attach附加整个对象图并维护导航属性。 Detach分离唯一的单实体不相关的对象和破坏导航属性。 从上面链接的同一页面:

分离仅影响传递给方法的特定对象。 如果正在分离的对象在对象上下文中具有相关对象,则不会分离这些对象。

我可以想象这就是为什么DbContext API没有明确的Detach方法(与ObjectContext相反)的主要原因 - 分离被认为是一种高级功能,它的行为与人们的预期不同。

MSDN提到将对象从上下文“保存资源”中分离的唯一原因(再次上面的文章):

在Entity Framework应用程序中,您可以从对象上下文中分离对象。 您可以分离对象以节省资源,因为在同一对象上下文中执行重复查询会增加对象上下文的内存要求。

我认为这个方法没有准备好和设计用于在它们与上下文分离后处理它们。 它的主要目的是释放它们以立即进行垃圾收集。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM