DbContext 的通用合并:如何检查实体是不是已附加?

Posted

技术标签:

【中文标题】DbContext 的通用合并:如何检查实体是不是已附加?【英文标题】:Generic Merge of DbContext: how to check if entity is all ready attached?DbContext 的通用合并:如何检查实体是否已附加? 【发布时间】:2015-08-15 04:08:18 【问题描述】:

给定以下代码:

    void MergeDbContext(DbContext aSourceDbContext, DbContext aDestinationDbContext)
    
        var sourceEntities = aSourceDbContext.ChangeTracker.Entries().ToList();
        foreach (DbEntityEntry entry in sourceEntities)
        
            object entity = entry.Entity;
            entry.State = EntityState.Detached;

            // check if entity is all ready in aDestinationDbContext if not attach
            bool isAttached = false;// TODO I don't know how to check if it is all ready attched.
            if (!isAttached)
            
                aDestinationDbContext.Set(entity.GetType()).Attach(entity);
            
        
    

我如何一般地确定一个实体是否存在于上下文中。

【问题讨论】:

***.com/questions/6018711/… 如果有关联和修改实体,这会不会很复杂?您打算保留修改吗? @jjj 每个 DBContext 只能执行 1 个异步查询,并且我想执行多个以提高性能。所以我创建了 2 个 DBcontext,在这里我试图合并结果。对于我的特定实例,这些将​​是只读的并且没有更改。 【参考方案1】:

这是一个扩展方法,它通过以下步骤在上下文的状态管理器中查找对象:

获取类型的关键属性 获取对象的键值 检查上下文中是否有任何实体具有对象的类型和键值。
public static bool IsAttached<T>(this DbContext context, T entity)
    where T : class

    if (entity == null) return false;

    var oc = ((IObjectContextAdapter)context).ObjectContext;

    var type = ObjectContext.GetObjectType(entity.GetType());

    // Get key PropertyInfos
    var propertyInfos = oc.MetadataWorkspace
          .GetItems(DataSpace.CSpace).OfType<EntityType>()
          .Where(i => i.Name == type.Name)
          .SelectMany(i => i.KeyProperties)
          .Join(type.GetProperties(), ep => ep.Name, pi => pi.Name, (ep,pi) => pi);

    // Get key values
    var keyValues = propertyInfos.Select(pi => pi.GetValue(entity)).ToArray();

    // States to look for    
    var states = System.Data.Entity.EntityState.Added|System.Data.Entity.EntityState.Modified
                |System.Data.Entity.EntityState.Unchanged|System.Data.Entity.EntityState.Deleted;

     // Check if there is an entity having these key values
    return oc.ObjectStateManager.GetObjectStateEntries(states)
             .Select(ose => ose.Entity).OfType<T>()
             .Any(t => propertyInfos.Select(i => i.GetValue(t))
                                    .SequenceEqual(keyValues));

用法:

bool isAttached = dbContext.IsAttached(entity);

【讨论】:

keyprops 的设置出现以下异常。 “找不到 EntityType 'System.Object' 的映射和元数​​据信息。”我认为是因为实体属于代理类型。 bool isAttached = aDestinationDbContext.IsAttached(entity);我是怎么称呼它的......是的,我不知道实体类型,因为我试图一般地合并两个上下文 这样可以解决异常,但是总是会返回 false。在“entity.GetType().Name”上设置监视变量我得到:“Parent_D6C692F519B2A9BA4C1E11ABFBC4086C28421AD0E3114091C3BA5A9D71089899”“entity.GetType().BaseType.Name”返回“Parent” var typename = typeof(T).Name; // 确实产生 Object 的“Object”。但是鉴于我正在尝试合并两个通用 dbcontexts,我怎么知道类型? 我不能不管这个,我终于解决了。我的错误是认为代理 inherently 总是返回基类型作为它的类型。但这只是因为大多数返回代理的方法将它们 cast 到它们的基本类型。这正是这里不会发生的事情。所以我不得不重写发现关键属性的方法。

以上是关于DbContext 的通用合并:如何检查实体是不是已附加?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Lazyloading,如何在处理完其 DBContext 后使用新的 DbContext 加载相关对象?

Entity Framework :Using Transaction Scope 如何检查 DbContext 是不是有事务?

如何从实体框架 DbContext 收集当前的 SQL Server 会话 ID?

DbContext通用数据仓储类

找出实体是不是附加到 dbContext 的最合理方法是啥?

如何更新在 DbContext 之外修改的实体?