使用继承的EF Core Fluent API配置

5

将EF CORE Fluent Api配置在单独的文件中,对于简单类Ref #1Ref #2可以正常工作。问题出现在实体继承自KeyedEntityAuditableEntity时。

class abstract KeyedEntity<TValue> {
      public TValue Id {get; set;}
}

class abstract  AuditableEntity<TValue> : KeyedEntityBase<TValue>{
      public DateTime DateCreated {get; set;}
      public DateTime DateModified {get; set;}
}

映射器大致如下

public class KeyedEntityMap<TEntity, TId>
    : IEntityTypeConfiguration<TEntity> where TEntity
    : KeyedEntityBase<TId> where TId : struct
{
    public void Configure(EntityTypeBuilder<TEntity> builder)
    {
        // Primary Key
        builder.HasKey(t => t.Id);

        // Properties
        builder.Property(t => t.Id).HasColumnName("id").ValueGeneratedOnAdd();
    }
}

public class AuditableEntityMap<TEntity, TId>
    : IEntityTypeConfiguration<TEntity>    where TEntity 
    : AuditableEntity<TId>    where TId : struct
{
    public void Configure(EntityTypeBuilder<TEntity> builder)
    {
        // Properties
        builder.Property(t => t.DateCreated).HasColumnName("DateCreated");
        builder.Property(t => t.DateModified).HasColumnName("DateModified");           
    }
}

现在问题出现在继承自的实体上。我需要注册该特定实体类的映射,以及类和类。现在,我可以忘记映射继承,并将所有复杂的继承映射合并到实体类中,但我不想这样做,而是遵循DRY原则。复杂继承的问题在于它无法注册我的实体映射。
1个回答

10

有几种方法可以实现基本实体配置的DRY。

但最接近您当前设计的方法是简单地遵循配置类中的实体层次结构:

public class KeyedEntityMap<TEntity, TId> : IEntityTypeConfiguration<TEntity>
    where TEntity : KeyedEntityBase<TId>
    where TId : struct
{
    public virtual void Configure(EntityTypeBuilder<TEntity> builder)
    //       ^^^
    {
        // Primary Key
        builder.HasKey(t => t.Id);

        // Properties
        builder.Property(t => t.Id).HasColumnName("id").ValueGeneratedOnAdd();
    }
}

public class AuditableEntityMap<TEntity, TId> : KeyedEntityMap<TEntity, TId>
    //                                                 ^^^
    where TEntity : AuditableEntity<TId>
    where TId : struct
{
    public override void Configure(EntityTypeBuilder<TEntity> builder)
    //       ^^^
    {
        base.Configure(builder); // <<<
        // Properties
        builder.Property(t => t.DateCreated).HasColumnName("DateCreated");
        builder.Property(t => t.DateModified).HasColumnName("DateModified");           
    }
}

然后对于需要额外配置的特定实体:

public class Person : AuditableEntity<int>    
{
    public string Name { get; set; }
}

您需要进行注册

public class PersonEntityMap : AuditableEntityMap<Person, int>
{
    public override void Configure(EntityTypeBuilder<Person> builder)
    {
        base.Configure(builder);
        // Properties
        builder.Property(t => t.Name).IsRequired();
        // etc...
    }
}

如果我想根据它们的结构类型或实体类型生成器类型配置属性怎么办? - liqSTAR
1
@liqSTAR 不确定你所说的“它们的结构”类型是什么意思。还有实体类型。基本实体意味着共同的属性是相同的,因此构建器用于配置它们。如果它们不同,则它们不是“基本”的。请注意,EF实体表示真实数据模型-需要具有真实类型的真实属性,而不是抽象接口或其他OOP内容。 - Ivan Stoev
好的,让我简单描述一下。您允许将结构体作为TId。我希望在添加ValueGeneratedOnAdd时生成一个Guid值,但如果它是一个int,我想使用UseIdentityColumn方法。 - liqSTAR
1
@liqSTAR,这通常是按照惯例完成的。但如果您愿意,您始终可以在基本配置中使用条件块。例如:if (typeof(TId) == typeof(Guid)) builder.Property(t => t.Id).ValueGeneratedOnAdd(); else if (..) else ... 等等。 - Ivan Stoev
@IvanStoev 大师级作品! - smrsgv
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接