Search code examples
c#entity-frameworkgraphdiff

How to update an expression tree with GraphDiff


The object graph I'm working with is basically:

public class Resource
    {
        public string Forename { get; set; }
        public string Surname { get; set; }
        public int EmployeeNumber { get; set; }
        public ICollection<Skill> Skills { get; set; }
    }
public class Skill
    {
        public int SkillId{get; private set;}
        public Technology Technology { get; set; }
        public SkillCategory Category { get; set; }
        public SkillCompetency Competency { get; set; }    

    }

A new skill can be added to the user by selecting combinations of existing Technology, SkillCategory, SkillCompetency. I've been trying (and failing!) to use GraphDiff to prevent EF from trying to add duplicate Technology, SkillCategory, SkillCompetency records. This seems like it should be simple to achieve using GraphDiff but being a relative newby to EF couple with only just finding GraphDiff I'm struggling.

Any ideas?


Solution

  • GraphDiff basically distinguishes two kinds of relations: owned and associated. Owned can be interpreted as "being a part of" meaning that anything that is owned will be inserted/updated/deleted with its owner. The other kind of relation handled by GraphDiff is associated which means that only relations to, but not the associated entities themselves are changed by GraphDiff when updating a graph.

    Coming back to your scenario: you don't want duplicate Technology, Category or Competency entities, but Skills are just combinations of those, so duplicate Skills are fine. To model this using GraphDiff, you tell it to consider Skills as parts of a Resource (owned by a Resource) and Technology, Category and Competency as associations of a Skill. This is mapped like so:

    // these three entities are all managed separately and have already been saved elsewhere
    Technology entityFrameworkCodeFirst;
    Category objectRelationalMappers;
    Competency notThatIncompetent;
    
    using (DbContext context = new WhatEverYourContextIsNamed())
    {
        Resource developer = new Resource
        {
            Skills = new List<Skill> 
            {  
                new Skill
                {
                    Technology = entityFrameworkCodeFirst,
                    Category = objectRelationalMappers,
                    Competency = notThatIncompetent,
                }
            } 
        };
        context.UpdateGraph(developer, 
            map => map.OwnedCollection(r => r.Skills, 
                with => with.AssociatedEntity(skill => skill.Technology)
                            .AssociatedEntity(skill => skill.Category)
                            .AssociatedEntity(skill => skill.Competency)));
        context.SaveChanges();
    }