EF:在DbContext上禁用“AutoDetectChangesEnabled”和“ProxyCreationEnabled”时,从多对多关系创建/删除关系
-
知道
Foo.Id
和Bar.Id
如何在不加载DB实体的情况下创建关系。class Foo { public int Id { get; set; } public Lst Bars { get; set; } } class Bar { public int Id { get; set; } public Lst Foos { get; set; } }
此配置也在
DbContext
构造函数中禁用:Configuration.AutoDetectChangesEnabled = false; Configuration.ProxyCreationEnabled = false; Configuration.LazyLoadingEnabled = false;
-
以及如何删除这种关系?
例:
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() }; var bar = new Bar { Id = 3, Foos = new List() }; // This approach wont work, as AutoDetectChanges are disabled ctx.Foos.Attach(foo); ctx.Bars.Attach(bar); foo.Bars.Add(bar); ctx.SaveChanges(); }
如何在不更改配置的情况下在此处定义关系。
先感谢您。
好的,找到了解决方案,这里是帮助方法:
static void ChangeRelationship( IObjectContextAdapter ctx, T1 a, T2 b, Expression> getNavigationProperty, EntityState state) where T1: class { ctx .ObjectContext .ObjectStateManager .ChangeRelationshipState( a, b, getNavigationProperty, state ); }
并在我的例子中使用它来自问题:
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()}; var bar = new Bar { Id = 3, Foos = new List() }; 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(); }
如果我理解正确,您希望将Bar对象添加到现有的Foo实体,而无需查找Foo实体。
比方说,你有Foo(id = 1)已经存在。 想要添加新的Bar(id = 100)实体。
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(); }
你问的是可能的。 以下是步骤:
(1)首先创建两个仅指定PK的实体实例,并将其中一个(例如foo
)附加到上下文中:
var foo = new Foo { Id = fooId }; var bar = new Bar { Id = barId }; ctx.Foos.Attach(foo);
(2)将第二个实体集合设置为包含第一个实体的新列表(即“创建”关系):
bar.Foos = new List { foo };
(3)将第二个实体标记如下:
(A)增加关系:
ctx.Entry(bar).State = EntityState.Added;
(B)删除关系:
ctx.Entry(bar).State = EntityState.Deleted;
(4)将第二个实体标记为未更改:
ctx.Entry(bar).State = EntityState.Unchanged;
就是这样!
一旦你调用ctx.SaveChanges();
,将在联结表中添加或删除关系。
更新:虽然上面的工作(实际上我的原始解决方案附加第二个实体与“原始”集合,然后模拟修改也有效,如果我们最后调用DbContext.ChangeTracker.DetectChanges()
显式),我应该承认ObjectContext
你发现的解决方案看起来更自然(奇怪的是,这种function还没有通过DbContext
),所以我的个人投票就在那里。