GetEntityTypes:使用EF Core中的.Property <TEntity>的通用版本配置实体属性

iPa*_*h ツ 3 c# entity-framework entity-framework-core ef-core-2.0

在我的EF核心项目中,我有一些从基类DBEntity继承的实体:

public abstract class DBEntity
{
    public int Id { get; set; }

    public DateTime CreatedOn { get; set; }

    public DateTime UpdatedOn { get; set; }

    public EntityStatus EntityStatus { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我想为从DBEntity继承的每个实体设置一些具有默认值的特定属性.目前我正在使用此代码:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

        var entities = modelBuilder.Model
            .GetEntityTypes()
            .Where(w => w.ClrType.IsSubclassOf(typeof(DBEntity)))
            .Select(p => modelBuilder.Entity(p.ClrType));

        foreach (var entity in entities)
        {

            entity
                .Property("CreatedOn")
                .HasDefaultValueSql("GETDATE()");

            entity
                .Property("UpdatedOn")
                .HasComputedColumnSql("GETDATE()");

            entity
                .Property("EntityStatus")
                .HasDefaultValue(EntityStatus.Created);

        }
    }
Run Code Online (Sandbox Code Playgroud)

这工作正常,但我不想使用字符串常量指定属性名称(对于重构等不好).

有没有办法循环从DBEntity继承的实体并使用属性表达式配置默认值,如下所示:

foreach (var entity in entities)
{
    entity
      .Property(k => k.CreatedOn)
      .HasDefaultValueSql("GETDATE()");

// ....

}
Run Code Online (Sandbox Code Playgroud)

重要约束:我不能直接调用modelBuilder.Entity().Property(k => k.CreatedOn)因为它会搞乱所有表.

Iva*_*oev 5

正如评论中指出的那样,你可以简单地用字符串常量替换nameof(DBEntity.CreatedOn)等.

但是,如果要使用类型化访问器,可以将基本实体配置代码移动到泛型方法(泛型参数是实际实体类型)并通过反射调用它.

例如,将以下内容添加到DbContext派生类中:

static void ConfigureDBEntity<TEntity>(ModelBuilder modelBuilder)
    where TEntity : DBEntity
{
    var entity = modelBuilder.Entity<TEntity>();

    entity
        .Property(e => e.CreatedOn)
        .HasDefaultValueSql("GETDATE()");

    entity
        .Property(e => e.UpdatedOn)
        .HasComputedColumnSql("GETDATE()");

    entity
        .Property(e => e.EntityStatus)
        .HasDefaultValue(EntityStatus.Created);

}
Run Code Online (Sandbox Code Playgroud)

然后使用这样的东西:

var entityTypes = modelBuilder.Model
        .GetEntityTypes()
        .Where(t => t.ClrType.IsSubclassOf(typeof(DBEntity)));

var configureMethod = GetType().GetTypeInfo().DeclaredMethods.Single(m => m.Name == nameof(ConfigureDBEntity));
var args = new object[] { modelBuilder };
foreach (var entityType in entityTypes)
    configureMethod.MakeGenericMethod(entityType.ClrType).Invoke(null, args);
Run Code Online (Sandbox Code Playgroud)