2

私はEFにかなり慣れていないので、次の問題で少し立ち往生しているようです..

次のような状況があります。

2 つのアプリケーションが同じデータベースを使用しており、両方が同時にコンテキストをロードして同じ情報を表示しています。
次に、アプリケーション 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);
            }
        }
    }
4

0 に答える 0