Dbset<TEntity>.Add (entity) назначает идентификатор, и это приводит к исключению
Для следующих классов:
public Car
{
public int ID { get; set; }
public string Brand {get; set; }
}
Обычно, когда мы делаем:
Car c = new Car { Brand = "Jaguar" } ; // Point A
context.Cars.Add(c); // Point B
context.SaveChanges() // Point C
В точке B идентификатор должен оставаться равным 0, а идентификатор должен назначаться только в точке C. Однако я обнаружил, что для одного из моих классов идентификатор назначается в точке B, и в результате возникает исключение:
Невозможно вставить явное значение для столбца идентификаторов в таблице "Автомобили", если для параметра IDENTITY_INSERT установлено значение OFF.
Я играл с Fluent API, и я на 99% уверен, что мои отношения определены правильно. Я не могу понять, почему этот DbSet пытается назначить идентификатор для этой сущности.
Обновить
Спасибо за вашу помощь, поэтому вот более подробная иллюстрация моей ситуации:
public Car
{
public int ID { get; set; }
public string Brand {get; set; }
public int Driver1ID {get; set;}
public Person Driver1 {get; set;}
public int Driver2ID {get; set;}
public Person Driver2 {get; set;}
}
public Person
{
public int ID { get; set; }
public string Name { get; set; }
}
И вот моя беглая конфигурация:
modelBuilder.Entity<Car>().HasKey(x => x.ID);
modelBuilder.Entity<Car>().Property(x => x.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // Added following Igor's suggestion
modelBuilder.Entity<Car>().HasRequired(x => x.Driver1).WithOptional().WillCascadeOnDelete(false);
modelBuilder.Entity<Car>().HasRequired(x => x.Driver2).WithOptional().WillCascadeOnDelete(false);
Редактировать 2
Ну, я обнаружил, что на самом деле перепутали Миграции. По какой-то причине EF поместил второй внешний ключ (Driver2) в столбец первичного ключа. Вот почему DbSet.Add() заполнял столбец идентификатора значением, фактически являющимся идентификатором драйвера 2.
Я действительно не знаю, почему EF так запутался. И странно то, что я не видел этот FK, когда смотрел в SQL Management Studio. Похоже, EF применил некоторые отношения, которых на самом деле не было в БД.
Я сбросил все миграции (удалил папку миграции и таблицу _migrationhistory, затем выполнил Enable-Migrations и Add-Migration Init в PowerShell), и мне удалось увидеть проблемные строки в исходном файле миграции.
Или, конечно, я изменил их, и, кажется, решил проблему.
2 ответа
В своем беглом (а также упрощенном) отображении вы можете указать, назначен ли идентификатор базой данных с использованием Identity или нет. Если вы укажете, что он назначен, ваш код также не должен назначаться, потому что вы получите исключение. В свободное время вы можете сделать это так:
public Car
{
public int ID { get; set; }
public string Brand {get; set; }
public int Driver1ID {get; set;}
public Person Driver1 {get; set;}
public int Driver2ID {get; set;}
public Person Driver2 {get; set;}
}
public Person
{
public int ID { get; set; }
public string Name { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder) {
// ....
modelBuilder.Entity<Car>().HasKey(x => x.ID);
modelBuilder.Entity<Car>().Property(x => x.ID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity); // set it on
modelBuilder.Entity<Car>().HasRequired(x => x.Driver1).WithMany().HasForeignKey(x => x.Driver1ID).WillCascadeOnDelete(false);
modelBuilder.Entity<Car>().HasRequired(x => x.Driver2).WithMany().HasForeignKey(x => x.Driver2ID).WillCascadeOnDelete(false);
// ....
}
Вы можете приписать столбец Id с
public Car
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Brand {get; set; }
}