Entity Framework (EF6) вставка или обновление, если существует для свойств - PullRequest
0 голосов
/ 15 ноября 2018

Предполагается, что модель будет выглядеть следующим образом:

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

Это исключение:

Нарушение PRIMARY KEYограничение 'PK_dbo.Bar'.Невозможно вставить дубликат ключа в объект 'dbo.Bar'.Значение дубликата ключа (Hello).

Как я могу объяснить EF, что если объект Bar имеет тот же ключ (или Id, или оба), что он считается одним и тем же экземпляром?

Я знаю, что если бы я мог сделать что-то вроде

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

Это бы хорошо работало.Однако, поскольку это данные, поступающие из внешнего источника, это невозможно сделать напрямую.Мой реальный сценарий имеет несколько уровней и много свойств.Поэтому я хотел бы решить это в модели.

1 Ответ

0 голосов
/ 15 ноября 2018

Вместо добавления сущностей, вы должны использовать библиотеку "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 раньше, друг порекомендовал его мне некоторое время назад, еще не было времени для дальнейших экспериментов с ним.

...