Update Many-to-Many Association with GraphDiff

c# entity-framework-6 graphdiff

Question

I have the following data model:

Data Model

My business logic works with detached entities so I'm using GraphDiff to perform updates. I'm having trouble updating the PerfModes/CalcPoints association. Conceptually, Block owns CalcPoints and PerfModes, but CalcPoints can be associated with any number of PerfModes.

I'm trying to do updates at the Block level. The code I came up with doesn't throw any errors (while other attempts did) but neither does it update the PerfModes/CalcPoints association.

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)
);

I probably don't have a full grasp of EF graphs and GraphDiff. How do I ensure that the many-to-many PerfModes/CalcPoints association gets updated correctly?

EDIT

After looking over andyp's answer, I pulled down the latest version of GraphDiff from GitHub and tried the following mappings:

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

This correctly updates my PerfModes/CalcPoints association. I switched back to my original mappings and still saw the issue of the association not updating, so it seems there's a problem with trying to update the entire model at once. I'd be fine with making multiple UpdateGraph calls, but what would be the best way to break them out?

Here's a gist with relevant code and a failing unit test.

I'm inheriting the EF generated container class to create my own context with proxy creation disabled. Does that cause a problem with GraphDiff?

1
3
5/29/2014 4:37:43 PM

Accepted Answer

As your mappings seemed to be correct, I've tried to reproduce your issue like this:

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]);
}

All entities are simple POCOs with an int key and just IDbSet<T>s on my DbContext. I've neither added anything in OnModelCreating(..) via the fluent API nor used any attributes on the navigation properties.

My code above is working properly, so I've got a couple of suggestions / questions:

  • Is there anything (significant) you did differently then me above?
  • Do you call SaveChanges() after UpdateGraph()? It's not implied!
  • Do you have the latest version of GraphDiff? Please note, that the NuGet package is quite outdated, it's better to grab the current source from Github and build it yourself.
  • If your problem persists please update your question with the exact scenario that isn't working: please include the state of your DbContext before calling UpdateGraph(), the changes you expect GraphDiff to make and the ones it fails to make.

EDIT: Your mapping wasn't correct after all, you're mapping Block.CalcPoints twice, once as an owned collection (first call to OwnedCollection(..)) and once as an associated collection (last and only call to AssociatedCollection(..)). So you never told GraphDiff to map PerfModes.CalcPoints and it, in turn, never updates that collection.. ;-)

To ask GraphDiff to do that please move one ) from the end of the line before the last line to the end of the last line and you should be fine (after that your indentation matches the brackets). The correct mapping looks like this (two closing brackets at the end of the last line):

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))
);
2
5/28/2014 6:51:50 PM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow