附加/添加与DB Context分离的实体对象的问题?

时间:2013-07-31 14:04:40

标签: c# database entity-framework dbcontext

我对EF很新,似乎对以下问题感到有些困惑..

我有以下情况。

两个应用程序使用相同的数据库,并同时加载上下文显示相同的信息 然后,应用程序1将删除实体并使用savechanges更新数据库。 然后,应用程序2继续并保存相同的修改实体。

我们正在使用updategraph来递归树并将所有实体保存到数据库上下文中。 但是,当我们保存已删除的实体时,从数据库获取的db上下文中不存在这种情况,但我们希望将其添加回数据库。

我尝试过做一个ADD,但这会给我们一个多重性错误,因为它试图将完整的树添加回上下文!

有什么想法吗?

以下是updategraph扩展方法的代码片段。 (http://github.com/refactorthis/GraphDiff

private static void RecursiveGraphUpdate<T>(DbContext context, T dataStoreEntity, T updatingEntity, UpdateMember member) where T:class
    {
        if (member.IsCollection)
        {
            // We are dealing with a collection
            var updateValues = (IEnumerable)member.Accessor.GetValue(updatingEntity, null);
            var dbCollection = (IEnumerable)member.Accessor.GetValue(dataStoreEntity, null);
            var keyFields = context.GetKeysFor(updateValues.GetType().GetGenericArguments()[0]);
            var dbHash = MapCollectionToDictionary(keyFields, dbCollection);

            // Iterate through the elements from the updated graph and try to match them against the db graph.
            List<object> additions = new List<object>();
            foreach (object updateItem in updateValues)
            {
                var key = CreateHash(keyFields, updateItem);

                // try to find in db collection
                object dbItem;
                var itemID = updateItem.GetType().GetProperty("ID");

                if (dbHash.TryGetValue(key, out dbItem))
                {

                    var property = updateItem.GetType().GetProperty("Deleted");
                    bool ysn = property.GetValue(updateItem, null).ToString() == "True" ? true : false;
                    if (ysn)
                    {
                        context.Entry(dbItem).CurrentValues.SetValues(updateItem);
                        continue;
                    }

                    // If we own the collection
                    if (member.IsOwned)
                    {
                        context.Entry(dbItem).CurrentValues.SetValues(updateItem); // match means we are updating

                        foreach (var childMember in member.Members)
                            RecursiveGraphUpdate(context, dbHash[key], updateItem, childMember);
                    }

                    dbHash.Remove(key); // remove to leave only db removals in the collection
                }

                else
                    additions.Add(updateItem);
            }

            // Removal of dbItem's left in the collection
            foreach (var dbItem in dbHash.Values)
            {
                var property = dbItem.GetType().GetProperty("Deleted");
                bool ysn = property.GetValue(dbItem, null).ToString() == "True" ? true : false;
                if (ysn)
                {
                    // Own the collection so remove it completely.
                    if (member.IsOwned)
                        context.Set(dbItem.GetType()).Remove(dbItem);

                    dbCollection.GetType().GetMethod("Remove").Invoke(dbCollection, new[] { dbItem });
                }
            }

            // Add elements marked for addition
            foreach (object newItem in additions)
            {
                if (!member.IsOwned)
                    context.Set(newItem.GetType()).Attach(newItem);

                // Otherwise we will add to object
                dbCollection.GetType().GetMethod("Add").Invoke(dbCollection, new[] { newItem });
            }
        }
        else // not collection
        {
            var dbvalue = member.Accessor.GetValue(dataStoreEntity, null);
            var newvalue = member.Accessor.GetValue(updatingEntity, null);
            if (dbvalue == null && newvalue == null) // No value
                return;

            // If we own the collection then we need to update the entities otherwise simple relationship update
            if (!member.IsOwned)
            {
                if (dbvalue != null && newvalue != null)
                {
                    var keyFields = context.GetKeysFor(newvalue.GetType());
                    var newKey = CreateHash(keyFields, newvalue);
                    var updateKey = CreateHash(keyFields, dbvalue);
                    if (newKey == updateKey)
                        return; // do nothing if the same key
                }

                if (context.Entry(newvalue).State == EntityState.Detached)
                    context.Set(newvalue.GetType()).Attach(newvalue);

                member.Accessor.SetValue(dataStoreEntity, newvalue, null);
                context.Entry(newvalue).Reload();
                // TODO would like to do this: context.Entry(newvalue).State = EntityState.Unchanged;
                // However it seems even though we are in an unchanged state EF will still update the database if the original values are different.
            }
            else
            {
                if (dbvalue != null && newvalue != null)
                {
                    // Check if the same key, if so then update values on the entity
                    var keyFields = context.GetKeysFor(newvalue.GetType());
                    var newKey = CreateHash(keyFields, newvalue);
                    var updateKey = CreateHash(keyFields, dbvalue);

                    // perform update if the same
                    if (updateKey == newKey)
                    {
                        context.Entry(dbvalue).CurrentValues.SetValues(newvalue);
                        context.Entry(dbvalue).State = EntityState.Modified;
                    }
                    else
                        member.Accessor.SetValue(dataStoreEntity, newvalue, null);
                }
                else
                    member.Accessor.SetValue(dataStoreEntity, newvalue, null);

                // TODO
                foreach (var childMember in member.Members)
                    RecursiveGraphUpdate(context, dbvalue, newvalue, childMember);
            }
        }
    }

0 个答案:

没有答案
相关问题