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; }
}
Другие вопросы по тегам