Ввод ключей вручную с 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.

Другие вопросы по тегам