使用GraphDiff更新多对多关联

时间:2014-05-23 16:19:15

标签: c# entity-framework-6 graphdiff

我有以下数据模型:

Data Model

我的业务逻辑适用于分离的实体,所以我使用GraphDiff来执行更新。我在更新PerfModes / CalcPoints关联时遇到问题。从概念上讲,Block拥有CalcPoints和PerfModes,但CalcPoints可以与任意数量的PerfModes相关联。

我试图在Block级别进行更新。我提出的代码不会抛出任何错误(而其他尝试也会抛出),但它也不会更新PerfModes / CalcPoints关联。

container.UpdateGraph(block, map => map
    .OwnedCollection(b => b.HistPoints)
    .OwnedCollection(b => b.CalcPoints)
    .OwnedCollection(b => b.PerfModes, with => with
        .OwnedCollection(p => p.FilterCriterion, with2 => with2
            .OwnedCollection(fc => fc.Filters, with3 => with3
                .AssociatedEntity(f => f.OperatorType)
                .AssociatedEntity(f => f.CalcPoint))))
        .AssociatedCollection(p => p.CalcPoints)
);

我可能没有完全掌握EF图和GraphDiff。如何确保多对多PerfModes / CalcPoints关联得到正确更新?

修改

在查看了andyp的回答之后,我从GitHub中删除了最新版本的GraphDiff并尝试了以下映射:

container.UpdateGraph(block, map => map
    .OwnedCollection(b => b.CalcPoints)
    .OwnedCollection(b => b.PerfModes,
        with => with.AssociatedCollection(pm => pm.CalcPoints)));

这正确地更新了我的PerfModes / CalcPoints关联。我切换回原来的映射,仍然看到关联没有更新的问题,所以似乎尝试立即更新整个模型存在问题。我可以使用多个UpdateGraph调用,但是最好的方法是什么呢?

Here's一个带有相关代码和失败的单元测试的要点。

我继承了EF生成的容器类,以便在禁用代理创建的情况下创建自己的上下文。这会导致GraphDiff出现问题吗?

1 个答案:

答案 0 :(得分:2)

由于你的映射似乎是正确的,我试图重现你的问题:

var calcPoint = new CalcPoint();
var block = new Block
{
    CalcPoints = new List<CalcPoint> {calcPoint},
    PerfModes = new List<PerfMode> 
    {
        new PerfMode {CalcPoints = new List<CalcPoint> {calcPoint}}
    }
};

using (var context = new TestDbContext())
{
    context.UpdateGraph(block, map => map
        .OwnedCollection(b => b.CalcPoints)
        .OwnedCollection(b => b.PerfModes, 
            with => with.AssociatedCollection(pm => pm.CalcPoints)));

    context.SaveChanges();
}

using (var context = new TestDbContext())
{
    var reloaded = context.Blocks.Include("PerfModes.CalcPoints").Single();
    Assert.AreEqual(1, reloaded.CalcPoints.Count);
    Assert.AreEqual(1, reloaded.PerfModes.Count);
    Assert.AreEqual(1, reloaded.PerfModes[0].CalcPoints.Count);

    Assert.AreEqual(reloaded.CalcPoints[0], reloaded.PerfModes[0].CalcPoints[0]);
}

所有实体都是简单的POCO,带有一个int键,IDbSet<T>s只有DbContext。我既没有通过流畅的API在OnModelCreating(..)中添加任何内容,也没有使用导航属性中的任何属性。

我上面的代码工作正常,所以我有几个建议/问题:

  • 是否有任何(重要)你做的不同于我吗?
  • 您是否在SaveChanges()之后致电UpdateGraph()?这并不暗示!
  • 你有最新版的GraphDiff吗?请注意,NuGet包已经过时,最好从Github获取当前源并自行构建。
  • 如果您的问题仍然存在,请使用完全无效的情况更新您的问题:请在致电DbContext之前提供UpdateGraph()的状态,更改您期待GraphDiff和它未能制作的。

修改: 毕竟,您的映射不正确,您将Block.CalcPoints 映射两次,一次作为拥有的集合(第一次调用OwnedCollection(..)),一次作为关联集合(最后一次)并且只调用AssociatedCollection(..))。因此,您从未告诉GraphDiff映射PerfModes.CalcPoints,反过来,它永远不会更新该集合..; - )

要让GraphDiff这样做,请从最后一行之前的行末尾移动一个)到最后一行的末尾,你应该没问题(之后你的缩进与括号匹配)。正确的映射看起来像这样(最后一行末尾有两个右括号):

container.UpdateGraph(block, map => map
    .OwnedCollection(b => b.HistPoints)
    .OwnedCollection(b => b.CalcPoints)
    .OwnedCollection(b => b.PerfModes, with => with
        .OwnedCollection(p => p.FilterCriterion, with2 => with2
            .OwnedCollection(fc => fc.Filters, with3 => with3
                .AssociatedEntity(f => f.OperatorType)
                .AssociatedEntity(f => f.CalcPoint)))
        .AssociatedCollection(p => p.CalcPoints))
);