Ключ базового типа EF Core Migration не определен - PullRequest
0 голосов
/ 01 декабря 2018

Я настроил группу сущностей, которые наследуются от «базовой» сущности, которая содержит ключевое поле и 2 поля аудита времени даты:

/// <summary>
/// The <see cref="BaseEntity"/> class is a standard entity from which all other entities inherit.
/// </summary>
public abstract class BaseEntity
{
    /// <summary>
    /// Universal unique identifier for the entity.
    /// </summary>
    public Guid Guid { get; set; }

    /// <summary>
    /// Timestamp for when the entity was created.
    /// </summary>
    public DateTime CreatedAtTime { get; set; }

    /// <summary>
    /// Timestamp for when the entity was last updated.
    /// </summary>
    public DateTime UpdatedAtTime { get; set; }
}

Я настроил сущность, которая наследует этот абстрактный класс:

/// <summary>
/// A <see cref="MilitaryUnit"/> is a group of <see cref="MilitaryMember"/>'s that work together
/// and have a 'chain of command'
/// </summary>
public class MilitaryUnit : BaseEntity
{
    public string Name { get; set; }

    public string Description { get; set; }

    public virtual ICollection<MilitaryMember> Members { get; set; }

    public virtual ICollection<MilitaryUnitSection> Sections { get; set; }

    public MilitaryUnit()
    {
        this.Members = new HashSet<MilitaryMember>();
        this.Sections = new HashSet<MilitaryUnitSection>();
    }
}

В моем DbContext я создал DbSet, который ссылается на сущность MilitaryUnit, и применил конфигурацию:

DbContext

public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options) { }

public DbSet<MilitaryUnit> MilitaryUnits { get; set; }

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.ApplyConfiguration<MilitaryUnit>(new MilitaryUnitConfiguration());
}

MilitaryUnitConfiguration

public class MilitaryUnitConfiguration : IEntityTypeConfiguration<MilitaryUnit>
{
    public void Configure(EntityTypeBuilder<MilitaryUnit> builder)
    {
        // All entities inherit from the BaseEntity type
        builder.HasBaseType<BaseEntity>();

        // The unit name can only be 50 characters long and is unique
        builder.Property(entity => entity.Name)
                .HasColumnType("varchar(50)")
                .HasMaxLength(50)
                .IsRequired();

        builder.HasAlternateKey(entity => entity.Name);

        // The unit has a description that can be up to 100 character long
        builder.Property(entity => entity.Description)
                .HasColumnType("varchar(100)")
                .HasMaxLength(100);

        // The unit has multiple members
        builder.HasMany<MilitaryMember>(entity => entity.Members);

        // The unit has multiple sections
        builder.HasMany<MilitaryUnitSection>(entity => entity.Sections);
    }
}

Когда я пытаюсь применить миграцию, я получаю следующую ошибку:

Ключ не может быть настроен в 'MilitaryUnitпотому что это производный тип.Ключ должен быть настроен для корневого типа «BaseEntity».Если вы не собирались включать в модель «BaseEntity», убедитесь, что он не включен в свойство DbSet вашего контекста, не указан в вызове конфигурации для ModelBuilder или не указан в свойстве навигации для включенного типа.в модели.

Теперь у меня есть конфигурация модели для BaseEntity:

public class BaseEntityConfiguration : IEntityTypeConfiguration<BaseEntity>
{
    public void Configure(EntityTypeBuilder<BaseEntity> builder)
    {
        builder.HasKey(entity => entity.Guid);

        builder.Property(entity => entity.Guid)
                .HasColumnType("guid");

        builder.Property(entity => entity.CreatedAtTime)
                .HasColumnType("datetime")
                .HasValueGenerator(typeof(CurrentDateTimeGenerator))
                .ValueGeneratedOnAdd();

        // The updated timestamp has a default value of the minimum date time value and will only
        // generate a new date time when the entity has been updated
        builder.Property(entity => entity.UpdatedAtTime)
                .HasColumnType("datetime")
                .HasDefaultValue(DateTime.MinValue)
                .HasValueGenerator(typeof(CurrentDateTimeGenerator))
                .ValueGeneratedOnUpdate();
    }
}

... но я не уверен, где это применить!Я предполагал, что это было где-то в DbContext, но после попытки этого я все еще получаю ошибку (как упомянуто выше).Я схожу с ума и пропускаю что-то совершенно очевидное?

1 Ответ

0 голосов
/ 01 декабря 2018

Спасибо всем за ответы!Таким образом, кажется, что решение не было слишком ужасным:

Я установил класс BaseEntityConfiguration как абстрактный класс, который принимает тип сущности, который я хочу настроить, и реализую интерфейс IEntityTypeConfiguration и делаю метод Configure способнымбыть 'overidable'.

BaseConfiguration

public abstract class BaseEntityConfiguration<TEntityType> : IEntityTypeConfiguration<TEntityType>
    where TEntityType : BaseEntity
{
    public virtual void Configure(EntityTypeBuilder<TEntityType> builder)
    {
        builder.HasKey(entity => entity.Guid);

        // The created timestamp has a default value of the current system time for when the entity
        // was created in the database. This value cannot be changed after it is set
        builder.Property(entity => entity.CreatedAtTime)
                .HasColumnType("datetime")
                .HasValueGenerator(typeof(CurrentDateTimeGenerator))
                .ValueGeneratedOnAdd();

        // The updated timestamp has a default value of the minimum date time value and will only
        // generate a new date time when the entity has been updated
        builder.Property(entity => entity.UpdatedAtTime)
                .HasColumnType("datetime")
                .HasDefaultValue(DateTime.MinValue)
                .HasValueGenerator(typeof(CurrentDateTimeGenerator))
                .ValueGeneratedOnUpdate();
    }
}

Затем в классах конфигурации объекта я расширяю этот класс BaseEntityConfiguration и переопределяю метод Configure, одновременно выполняя базовый метод Configure из абстрактного класса:

public class MilitaryUnitConfiguration : BaseEntityConfiguration<MilitaryUnit>
{
    public override void Configure(EntityTypeBuilder<MilitaryUnit> builder)
    {
        base.Configure(builder);

        // The unit name can only be 50 characters long and is unique
        builder.Property(entity => entity.Name)
                .HasColumnType("varchar(50)")
                .HasMaxLength(50)
                .IsRequired();

        builder.HasAlternateKey(entity => entity.Name);

        // The unit has a description that can be up to 100 character long
        builder.Property(entity => entity.Description)
                .HasColumnType("varchar(100)")
                .HasMaxLength(100);

        // The unit has multiple members
        builder.HasMany<MilitaryMember>(entity => entity.Members);

        // The unit has multiple sections
        builder.HasMany<MilitaryUnitSection>(entity => entity.Sections);
    }
}

Хотя я не проверил это полностью, похоже, что миграция была успешно настроена:

migrationBuilder.CreateTable(
    name: "MilitaryUnits",
    columns: table => new
    {
        Guid = table.Column<Guid>(nullable: false),
        CreatedAtTime = table.Column<DateTime>(type: "datetime", nullable: false),
        UpdatedAtTime = table.Column<DateTime>(type: "datetime", nullable: false, defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified)),
        Name = table.Column<string>(type: "varchar(50)", maxLength: 50, nullable: false),
        Description = table.Column<string>(type: "varchar(100)", maxLength: 100, nullable: true)
    },
    constraints: table =>
    {
        table.PrimaryKey("PK_MilitaryUnits", x => x.Guid);
        table.UniqueConstraint("AK_MilitaryUnits_Name", x => x.Name);
    });
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...