Ввод ключей вручную с Entity Framework
Сначала я пытаюсь использовать код Entity Framework для простого проекта базы данных и сталкиваюсь с проблемой, которую просто не могу понять.
Я заметил, что EF устанавливает идентификатор для моих таблиц, автоматически увеличивая его на 1 каждый раз, полностью игнорируя значение, которое я ввел вручную для этого поля. После некоторых поисков я понимаю, что правильно отключить это поведение:
modelBuilder.Entity<Event>().Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
Однако сейчас я просто получаю эту ошибку, и я понятия не имею, почему:
Необработанное исключение: System.Data.Entity.Infrastructure.DbUpdateException: при обновлении записей произошла ошибка. Смотрите внутреннее исключение для деталей. ---
System.Data.UpdateException: при обновлении записей произошла ошибка. Смотрите внутреннее исключение для деталей. ---> System.Data.SqlClient.SqlException: Невозможно вставить явное значение для столбца идентификаторов в таблице "События", когда для IDENTITY_INSERT установлено значение OFF.
Если это полезно, вот рассматриваемый класс POCO:
public class Event
{
[Key, Required]
public int EventID { get; set; }
public string EventType { get; set; } //TODO: Event Type Table later on
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public virtual ICollection<Match> Matches { get; set; }
public virtual ICollection<EventParticipation> EventParticipation { get; set; }
}
Заранее спасибо.
2 ответа
По умолчанию Entity Framework предполагает, что целочисленный первичный ключ генерируется базой данных (эквивалентно добавлению атрибута HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity)
или звонит Property(e => e.EventID).HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
в свободном API.
Если вы посмотрите на миграцию, которая создает таблицу, вы должны увидеть это:
CreateTable(
"dbo.Events",
c => new
{
EventID = c.Int(nullable: false, identity: true),
//etc
})
.PrimaryKey(t => t.EventID );
Затем вы изменили модель с помощью Fluent API на DatabaseGenerated.None
, EF помещает это в миграцию:
AlterColumn("dbo.Events", "EventID", c => c.Int(nullable: false, identity: false))
И сгенерированный sql это:
ALTER TABLE [dbo].[Events] ALTER COLUMN [EventID] [int] NOT NULL
Который на самом деле делает приседания. Удаление IDENTITY из столбца не является тривиальным. Вам нужно удалить и заново создать таблицу или создать новый столбец, затем вам нужно скопировать данные и исправить внешние ключи. Так что не удивительно, что EF не делает это для вас.
Вы должны решить, как лучше сделать это для себя. Вы можете откатить ваши миграции до 0 и перестроить с нуля, теперь, когда вы указали DatabaseGeneratedOption.None
или вы можете изменить миграцию вручную, чтобы удалить и заново создать таблицу.
Или вы можете удалить и восстановить столбец:
DropColumn("Customer", "CustomerId");
AddColumn("Customer", "CustomerId", c => c.Long(nullable: false, identity: false));
РЕДАКТИРОВАТЬ Или вы можете включить / выключить идентификацию с помощью пользовательской операции миграции
Так как я предпочитаю атрибуты, вот альтернатива ради полноты:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
Примечание: это работает и в EF Core.