EF:在DbContext上禁用“AutoDetectChangesEnabled”和“ProxyCreationEnabled”时,从多对多关系创建/删除关系

时间:2016-09-26 17:01:44

标签: c# entity-framework entity-framework-6

  1. 知道Foo.IdBar.Id如何在不从数据库加载实体的情况下创建关系。

    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; }
    }
    

    此配置也在DbContext构造函数中禁用:

    Configuration.AutoDetectChangesEnabled = false;
    Configuration.ProxyCreationEnabled = false;
    Configuration.LazyLoadingEnabled = false;
    
  2. 如何删除这段关系?

  3. 示例:

    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();
    }
    

    如何在不更改配置的情况下在此处定义关系。

    提前谢谢。

3 个答案:

答案 0 :(得分:2)

好的,找到了解决方案,这里是帮助方法:

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
        );
}

在我的例子中使用它来自问题:

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();
}

答案 1 :(得分:1)

如果我理解正确,你想要将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();
}

答案 2 :(得分:1)

你问的是可能的。以下是步骤:

(1)首先创建两个仅指定PK的实体实例,并将其中一个(例如foo)附加到上下文中:

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

(2)将第二个实体集合设置为包含第一个实体的新列表(即&#34;创建&#34;关系):

bar.Foos = new List<Foo> { 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();后,将在联结表中添加或删除关系。

更新:虽然上述工作(实际上我的原始解决方案是将第二个实体附加&#34;原始&#34;集合然后模拟修改也可以在我们最后调用{明确地{1}},我应该承认,您找到的DbContext.ChangeTracker.DetectChanges()解决方案看起来更自然(这种功能尚未通过ObjectContext公开,这很奇怪),所以我的个人投票去那里。