4

我正在使用 GraphDiff 以及最新版本的实体框架,遵循代码优先的方法。

我正在尝试以Food这种方式更新实体:

public void Update(Food food)
{
    using (var db = new DatabaseMappingContext())
    {
        food = db.UpdateGraph(food, map => map.OwnedEntity(f => f.FoodRecipe, withRecipe => withRecipe.
               OwnedCollection(r => r.RecipeSteps, withRecipeStep => withRecipeStep.
                   OwnedCollection(rs => rs.StartObjectSlots, withStartObjectSlots => withStartObjectSlots.
                       AssociatedEntity(sos => sos.BelongingRecipeStepAsStart)
                   ).
                   OwnedCollection(rs => rs.EndObjectSlots, withEndObjectSlots => withEndObjectSlots.
                       AssociatedEntity(eos => eos.BelongingRecipeStepAsEnd)
                   ).
                   AssociatedEntity(rs => rs.ActionOfUser)
               ).
               AssociatedCollection(r => r.InteractiveObjects)
            ).
            AssociatedCollection(f => f.FoodVarieties));
        //....
        db.SaveChanges();
    }
}

StartObjectSlots并且EndObjectSlots是 2 个包含其他一些不相关数据的列表。InteractiveObjects包含一个类型的对象,InteractiveObject该类型是可以放置在那里的许多对象类型的基本类型。其中一种派生类型(假设IntObjDerived具有一对多属性)。现在,我正在尝试以这种方式更新以下实体:

ServerAdapter sa = new ServerAdapter();
//Loading a food from DB.
Food food = sa.LoadAllFoods().First();
RecipeStep rs = new RecipeStep();
rs.Name = "This is a test recipe step";
//Adding a User Action from the database.
rs.ActionOfUser = sa.LoadAllUserActions().First();
//....
//Add the step in the recipe
food.FoodRecipe.RecipeSteps.Add(rs);
//Update the food.
sa.Update(food);

现在,当代码被执行时,一个新的空 ActionOfUser 实体被插入到数据库中。此外,为上述实体的每个一对多导航属性插入一个新的空实体三个新配方被插入到数据库中,一个是空数据,一个是半满的,这个应该被保存。这两种情况都是不需要的,我正在努力寻找解决方案。我尝试了一些更改,但我一直坚持这一点。有什么建议么?(我知道这似乎是 2 个问题,但我想把它作为一个问题,因为它可能是数据库中相关的相同问题)。

编辑:我下载并编译GraphDiff以检查发生了什么,我注意到创建了一些空对象,除了它们的实体 ID 值。我猜这些副作用是因为实际上我在对象图中添加了一个新节点(一个新的 RecipeStep)而我不确定 graphdiff 是否完全支持这一点。

更新(tl; dr版本):我尝试UpdateGraph使用 Entity Framework 的 GraphDiff 对图形深度大于 2 的对象应用调用。根据我的尝试,似乎 GraphDiff 在深度大于 2 的图形中应用了双插入,并且需要很多时间,特别是如果添加了从数据库加载的子节点的新节点。我是否应该采用不同的方法,例如将UpdateGraph呼叫拆分为多个呼叫?

先感谢您!

4

1 回答 1

1

我最终应用的解决方法是通过将更新操作拆分为UpdateGraph图形深度小于或等于 2 的多个调用并手动将任何子节点添加到图形中来执行更新操作:

//Update food in total graph depth <= 2.
db.UpdateGraph(food, map => map.AssociatedCollection(f => f.FoodVarieties));

//.... (Other UpdateGraph calls with graph depth <=2)

//Update recipe steps of recipe in total graph depth <= 2.
foreach (RecipeStep recipeStep in food.FoodRecipe.RecipeSteps)
{
    recipeStep.ActionOfUser = db.UserActions.FirstOrDefault(ua => ua.EntityID == recipeStep.ActionOfUser.EntityID);

    //If you have to do an inner node adding operation in the graph, do it manually.
    if (recipeStep.EntityID == 0)
    {
        recipeStep.BelongingRecipe = db.Recipes.FirstOrDefault(r => r.EntityID == food.FoodRecipe.EntityID);
        db.RecipeSteps.Add(recipeStep);
    }
    else
    {
        //Map slots & recipeSteps applied manually here.
        recipeStep.StartObjectSlots.ForEach(sos => sos.BelongingRecipeStepAsStart = recipeStep);
        recipeStep.EndObjectSlots.ForEach(eos => eos.BelongingRecipeStepAsEnd = recipeStep);

        db.UpdateGraph(recipeStep, map => map.OwnedCollection(rs => rs.InteractiveObjectInstancesLists, withIOILists => withIOILists.
                OwnedCollection(ioil => ioil.InteractiveObjectsInstances)
            ).
            OwnedCollection(rs => rs.StartObjectSlots, withStartObjectSlots => withStartObjectSlots.
                AssociatedEntity(sos => sos.BelongingRecipeStepAsStart)
            ).
            OwnedCollection(rs => rs.EndObjectSlots, withEndObjectSlots => withEndObjectSlots.
                AssociatedEntity(eos => eos.BelongingRecipeStepAsEnd)
            ).
            AssociatedEntity(rs => rs.ActionOfUser)
        );

    }
}

此外,我注意到对象的图形更新完成得比以前快得多。这些可能表明复杂图形(>2 深度)更新过程中出现问题(或者至少我做错了什么GraphDiff

于 2014-12-25T12:27:52.973 回答