Updates to GraphDiff with new scenarios supported

Hi, This post will just be a quick update on the progress of GraphDiff.

It’s great that quite a few people are using/looking into GraphDiff. I have finally found some time and I am updating the code with numerous bug fixes and new features. I will be able to spend more time on this project now so if you have any issues please add them to github here .

There is a new official package on nuget called ‘RefactorThis.GraphDiff’ the only breaking change is a namespace change from GraphDiff to RefactorThis.GraphDiff. This package is a newer version and will receive all future updates you can get it here .

I also want to quickly clarify what AssociatedCollection and AssociatedEntity does as I’ve had some questions.

Associated/Owned clarification

If a person has a list of friends and you want to update the list of a friends for a person, but not update the entities inside that collection (such as that friend’s first name) then that friend collection is an associated collection and can be written like this:

context.UpdateGraph(person1, map => map.AssociatedCollection(person => person.friends));

if an update has been made to the friend entity we don’t want it to be saved, however we do want to save the fact that the person now has a new friend. This is what the associated collection does. An owned collection on the other hand will state that all of the entities inside of the friends collection are owned by the parent entity and will be updated, so the first name change will be saved to the database.

For more information please read my original post here

New Features/Fixes

  • Supports cyclic navigational properties
  • Now only performs updates of the parent and nested entities when needed (better support for auditing and concurrency scenarios)
  • Bugfix for complex graphs of collections of collections
  • Supports proxy objects (no lazy loading is done from within GraphDiff, all entities needed are loaded with one query) however the code did not support proxy objects.
  • Supports reloading entities that have been attached with the GraphDiffConfiguration.ReloadAssociatedEntitiesOnAttach configuration option. This is useful in cases where you may want to return the graph once saved. EF (by design) will returned the attached object not the object as it truely is in the database as the object exists in its local cache. The easy way to get around this is to simply make the database calls on a new context. If this is unavailable to you then you can set this configuration option and GraphDiff will ensure that any associated entities are updated from the database, ensuring you always receive the latest copy of all entities.
Advertisements

Introducing GraphDiff for Entity Framework Code First – Allowing automated updates of a graph of detached entities

Looking for a complete solution for automatically updating a graph of entities using the Entity Framework? Read On!

Hi, As usual I have neglected this blog as of late. It is getting harder and harder to find time to put some notes up here. But hopefully today I have something very interesting to make up for it.

So today I’m finally going to post something that we have actually been using live on our production code for quite some time, and the good news is that it is working beautifully. I’m introducing GraphDiff – an extension method allowing for the automatic update of a detached graph using Entity Framework code first. (Edit: code has been rewritten to handle multiple new features, as such no guarantee can be given on its production-ready usage, but I’m continuing to work on it to make sure it is relatively bug-free)

Working with detached graphs of entities we quite often found that it was cumbersome to use the Entity Framework to manually map all of the changes from an aggregate root to the database. By aggregate root I mean a bunch of models which are handled as one unit when updating/adding/deleting.

Below I will describe my proposed solution to this problem of automatically updating a detached graph consisting of multiple add/delete/update changes at any point in the graph. This should work for all sorts of graphs, and allows for updating entities with associated collections and single entities.

I find its always clearer with some code so lets try an example:

Say you have a Company which has many Contacts. A contact is not defined on its own and is a One-To-Many (with required parent) record of a Company. i.e. The company is the Aggregate Root. Assume you have a detached Company graph with its Contacts attached and want to reflect the state of this graph in the database.

At present using the Entity Framework you will need to perform the updates of the contacts manually, check if each contact is new and add, check if updated and edit, check if removed then delete it from the database. Once you have to do this for a few different aggregates in a large system you start to realize there must be a better, more generic way.

Well good news is that after a few refactorings I’ve found a nice solution to this problem. The proposed extension method below handles the whole diff for you in a nice convenient package.

using (var context = new TestDbContext())
{
    // Update the company and state that the company 'owns' the collection Contacts.
    context.UpdateGraph(company, map => map
        .OwnedCollection(p => p.Contacts)
    );

    context.SaveChanges();
}

Using the above code a diff will be run between the provided company graph and one retrieved from the database. The bounds of the graph are defined by the mapping which above is the company entity itself and its child Contacts. Only entities within these bounds will be included in the database diff.

The retrieval code makes use of the provided mapping configuration to get all data needed in one query at the start of the process, thus making the process quite efficient.

From this diff the algorithm will add/update/delete depending on what action needs to be performed and commit all of these changes in one batch at the end of the algorithm.

There are 2 different scenarios that this extension method must cater for. One is the situation above where you have a One-To-Many or One-To-One where the right hand side of the relationship is owned by the parent. This is defined within the mapping as an OwnedCollection/OwnedEntity.

The other scenario is that you have a Many-To-Many, or a One-To-Many and the related record exists in its own right as it not a defined part of the aggregate you are updating. That scenario is defined as an AssociatedCollection/AssociatedEntity.

The mapping configuration can handle many complex scenarios with ease. For example:

I have a company aggregate which is made of address objects and contact objects. On the contact model there is a list of accepted advertising materials (List) which are managed elsewhere in the system and not a part of the company aggregate. The list of advertisingOptions that are associated with the contact still needs to be updated however when managing the company as an aggregate.

using (var context = new TestDbContext())
{
    // Update the company and state that the company 'owns' the collection Contacts.
    context.UpdateGraph(company, map => map
        .OwnedCollection(p => p.Contacts, with => with
            .AssociatedCollection(p => p.AdvertisementOptions))
        .OwnedCollection(p => p.Addresses)
    );

    context.SaveChanges();
}

The associated collection line tells the update method that the actual entities that are AdvertisementOptions should not be marked as changed (even if the objects provided are different from the database values. We do however want to update the relation so that it reflects the fact that the contact has the provided AdvertisementOptions and this is performed during the update.

If you would like to use this code please leave all copyright marks as they are. The code has been put up on https://github.com/refactorthis/GraphDiff.

Hope this helps you as it did our team. Please note that there are a few things that can still be improved and if you have any suggestions please let me know.