EF: Create/Remove relation from Many-to-Many relations when `AutoDetectChangesEnabled` and `ProxyCreationEnabled` are disabled on DbContext

左心房为你撑大大i 提交于 2019-12-20 04:25:37

问题


  1. Knowning Foo.Id and Bar.Id how can I create their relation without loading the entities from the DB.

    class Foo {
        public int Id { get; set; }
        public Lst<Bar> Bars { get; set; }
    }
    
    class Bar {
        public int Id { get; set; }
        public Lst<Foo> Foos { get; set; }
    }
    

    Also this configuration are disabled in DbContext constructor:

    Configuration.AutoDetectChangesEnabled = false;
    Configuration.ProxyCreationEnabled = false;
    Configuration.LazyLoadingEnabled = false;
    
  2. And how it is possible to remove the relationship?


Example:

using (var ctx = new DbCtx())
{
    ctx.Configuration.LazyLoadingEnabled = false;
    ctx.Configuration.ProxyCreationEnabled = false;
    ctx.Configuration.AutoDetectChangesEnabled = false;
    ctx.Database.Log += Console.WriteLine;

    var foo = new Foo {Id = 1, Bars = new List<Bar>() };
    var bar = new Bar { Id = 3, Foos = new List<Foo>() };

    // This approach wont work, as AutoDetectChanges are disabled
    ctx.Foos.Attach(foo);
    ctx.Bars.Attach(bar);

    foo.Bars.Add(bar);
    ctx.SaveChanges();
}

How can I define relation here, without changing the configuration.

Thank you in advance.


回答1:


Ok, have found the solution and here is the helper method:

static void ChangeRelationship<T1, T2>(
    IObjectContextAdapter ctx, 
    T1 a, 
    T2 b, 
    Expression<Func<T1, object>> getNavigationProperty,
    EntityState state) where T1: class
{
    ctx
        .ObjectContext
        .ObjectStateManager
        .ChangeRelationshipState(
            a,
            b,
            getNavigationProperty,
            state
        );
}

And using it in my example from the question:

using (var ctx = new DbCtx())
{
    ctx.Configuration.LazyLoadingEnabled = false;
    ctx.Configuration.ProxyCreationEnabled = false;
    ctx.Configuration.AutoDetectChangesEnabled = false;
    ctx.Database.Log += Console.WriteLine;

    var foo = new Foo {Id = 1, Bars = new List<Bar>()};
    var bar = new Bar { Id = 3, Foos = new List<Foo>() };

    ctx.Entry(foo).State = EntityState.Unchanged;
    ctx.Entry(bar).State = EntityState.Unchanged;

    // create
    ChangeRelationship(ctx, foo, bar, x => x.Bars, EntityState.Added);
    ctx.SaveChanges();

    // remove
    ChangeRelationship(ctx, foo, bar, x => x.Bars, EntityState.Deleted);
    ctx.SaveChanges();
}



回答2:


If I'm understanding correctly, you wanted to add Bar object to an existing Foo entity without making a lookup for Foo entity.

Let say, you have Foo (id = 1) already exists. Wanted to add new Bar (id = 100) entity to it.

using (var context = new Context())
{
    var bar = new Bar() { Id = 100 };
    var foo = new Foo() { Id = 1 }; // Only ID is required

    context.Foos.Attach(foo);
    bar.Foos.Add(foo);

    context.Bars.Add(bar);
    context.SaveChanges();
}



回答3:


What you are asking is possible. Here are the steps:

(1) Start by creating two entity instances with just PK specified and attach one of them (for instance foo) to the context:

var foo = new Foo { Id = fooId };
var bar = new Bar { Id = barId };
ctx.Foos.Attach(foo);

(2) Set the second entity collection to a new list containing the first entity (i.e. "create" the relation):

bar.Foos = new List<Foo> { foo };

(3) Mark the second entity as follows:

(A) To add relation:

ctx.Entry(bar).State = EntityState.Added;

(B) To remove relation:

ctx.Entry(bar).State = EntityState.Deleted;

(4) Mark the second entity as unchanged:

ctx.Entry(bar).State = EntityState.Unchanged;

And that's it!

Once you call ctx.SaveChanges();, the relation will be added or removed from the junction table.

Update: While the above works (actually my original solution of attaching the second entity with the "original" collection and then simulating modification also works if we call at the end DbContext.ChangeTracker.DetectChanges() explicitly), I should admit that the ObjectContext solution you found looks much more natural (it's strange that such functionality has not been exposed via DbContext), so my personal vote goes there.



来源:https://stackoverflow.com/questions/39708439/ef-create-remove-relation-from-many-to-many-relations-when-autodetectchangesen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!