【问题标题】:Entity Framework (EF6) insert or update if exists for properties如果属性存在,实体框架 (EF6) 插入或更新
【发布时间】:2018-11-16 00:52:09
【问题描述】:

假设模型如下:

class Foo {
    virtual Bar Bar {get; set ;}
}

class Bar {
    int Id { get; set; }
    string Property {get; set;}
}

class MyContext {
     virtual DbSet<Foo> Foos {get; set;}

    void OnModelCreating(DbModelBuilder modelBuilder)
    {
         modelBuilder.Entity<Bar>()
            .HasKey(c => c.Property);
    }
}

还有一些类似的代码:

void DoStuff() {
   var foos = GetFoosFromExternalSource();

   using(var ctx = new MyContext() {
       foreach(var foo in foos) {
            ctx.Foos.Add(foo);
       }

       ctx.SaveChanges();
   }
}

IEnumerable<Foo> GetFoosFromExternalSource() {
     yield return new Foo {
          Bar = new Bar { Id = 1, Property = "Hello" }          
     };
     yield return new Foo {
          Bar = new Bar { Id = 2, Property = "World" }          
     };
     yield return new Foo {
          Bar = new Bar { Id = 1, Property = "Hello" }          
     }    
}

这会引发异常:

违反主键约束“PK_dbo.Bar”。无法在对象“dbo.Bar”中插入重复键。重复键值为 (Hello)。

我怎样才能让 EF 清楚,如果 Bar 对象具有相同的 Key(或 Id,或 Both),则它被视为同一个实例?

我知道如果我能做类似的事情

 IEnumerable<Foo> GetFoosFromExternalSource() {
     var bar1 = new Bar { Id = 1, Property = "Hello" };
     var bar2 = new Bar { Id = 2, Property = "World" };

     yield return new Foo {
          Bar = bar1          
     };
     yield return new Foo {
          Bar = bar2         
     };
     yield return new Foo {
          Bar = bar1
     }    
}

它会工作得很好。但是,由于这是来自外部来源的数据,因此这不可能直接实现。我的真实场景有多个层次和很多属性。所以我想在模型中解决这个问题。

【问题讨论】:

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


    【解决方案1】:

    您应该使用“upsert”库(或创建您自己的),而不是添加实体。例如FlexLabs.Upsert 就是这样一个用于 Entity Framework Core 的库。

    在您的情况下,代码将如下所示(基于文档):

    async Task DoStuff()
    {
       var foos = GetFoosFromExternalSource();
       using(var ctx = new MyContext()
       {
           await ctx.Foos
               .UpsertRange(foos)
               .On(f => f.Property)
               .RunAsync();
           ctx.SaveChanges(); // not sure if savechanges call is necessary based on docu...
       }
    }
    

    注意:我之前没用过FlexLabs.Upsert,前段时间朋友推荐给我了,还没来得及进一步试验。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-02-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-19
    相关资源
    最近更新 更多