Ошибка IDENTITY_INSERT ON с внешним ключом - PullRequest
0 голосов
/ 26 сентября 2018

Я пытаюсь установить Id вручную для некоторых записей.

У меня есть класс Customer с полем Identity

  modelBuilder.Entity<Customer>().Property(f => f.Id).HasDatabaseGeneratedOption(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity);

и в части вставки у меня есть

    using (var transaction = ctx.Database.BeginTransaction())
    {
      ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[Customers] ON");
      ctx.Customers.AddRange(customersList);
      ctx.SaveChanges();
      ctx.Database.ExecuteSqlCommand("SET IDENTITY_INSERT [dbo].[Customers] OFF");
      transaction.Commit();
    }

но я все еще получаю исключение

Для столбца идентификаторов в таблице «Клиенты» должно быть указано явное значение, когда для IDENTITY_INSERT задано значение ON или когда пользователь репликации вставляет встолбец идентификации NOT FOR REPLICATION.

В StateEntries моего исключения я вижу, что все поля, которые хранятся в другой таблице, такой как «Контакты», кажутся причиной customer.Contacts = new List<Contact> {new Contact {Name = "Test", … }}

Как мне заставить это работать?

1 Ответ

0 голосов
/ 26 сентября 2018

Это сообщение об ошибке вводит в заблуждение.Вы успешно включили IDENTITY_INSERT, но EF все еще генерирует инструкцию INSERT, предполагая, что значение ключа будет сгенерировано столбцом IDENTITY.

Таким образом, вы дополнительно должны сгенерировать оператор INSERT, содержащий значение ключа.Вы, конечно, можете использовать .ExecuteSqlCommand (), чтобы выполнить INSERT.Или вы можете заставить EF сделать это, но вы должны использовать модель, в которой у этого Entity нет ключей, сгенерированных базой данных.OnModelCreating настраивает модель только один раз для ModelType, поэтому вы не можете просто вставить туда переключатель.

Вместо этого вы можете создать подтип вашего DbContext для заполнения, переопределяя конфигурацию сущности базового DbContext.Например:

class Db_Seed: Db
{
    public Db_Seed(string constr) : base(constr)
    {
        Database.SetInitializer<Db_Seed>(null);  //no initializer
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.Entity<Customer>().Property(c => c.Id).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
    }
}

Вы все еще должны включить IDENTITY_INSERT (поскольку таблица имеет IDENTITY), но в этом контексте EF не будет генерировать инструкцию INSERT, предполагающую, что сервер будетсгенерировать ключ.

...