Search code examples
c#entity-frameworkentity-framework-4cycleinvalidoperationexception

How do I prevent InvalidOperationException saving a cyclic graph of entities?


Given the entities,

class A {
    B DefaultB { get; set; }
    C DefaultC { get; set; }
}

class B {
    A { get; set; }
}

class C {
    A { get; set; }
}

where A.DefaultB and A.DefaultC are optional,

modelBuilder.Entity<A>().HasOptional(x => x.DefaultB).WithMany();
modelBuilder.Entity<A>().HasOptional(x => x.DefaultC).WithMany(); 

what combination of context.Set<T>().Add(...) and context.SaveChanges() would work to save the following object graph?

var b = new B();
var c = new C();
var a = new A { DefaultB = b, DefaultC = c, };
b.A = a;
c.A = a;
// now save these...

As it is now, I get an InvalidOperationException (collection modification while iterating) because EF does not seem to handle cycles very well.


Solution

  • Hi you need to adjust your mapping:

    modelBuilder.Entity<A>().HasOptional(a => a.DefaultB);
    modelBuilder.Entity<A>().HasOptional(m => m.DefaultC);
    modelBuilder.Entity<B>().HasRequired(m => m.A);
    modelBuilder.Entity<C>().HasRequired(m => m.A);
    

    And the correct save order with this mapping:

    var a = new A() { Id = 3 };
    context.As.Add(a);
    context.SaveChanges();
    
    var b = new B() { Id = 1};
    var c = new C() { Id = 2 };
    context.Bs.Add(b);
    context.Cs.Add(c);
    b.A = a;
    c.A = a;
    a.DefaultB = b;
    a.DefaultC = c;
    context.SaveChanges();