如何在 OnModelCreating 中减少流利 API 的代码

How to reduce the code at fluent API in OnModelCreating

我在 table 中有几列不应该被任何未来的更新更改,所以我在 OnModelCreating 中使我的 API 流利如下。

base.OnModelCreating(builder);

builder.Entity<UserSetting>()
              .Property(p => p.ID)
                .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
builder.Entity<UserSetting>()
              .Property(p => p.CreatedOn)
                .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
builder.Entity<UserSetting>()
              .Property(p => p.CreatedBy)
                .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;

我的项目有40个table所以我用这个方法写了120行

与其写 120 行,还有更简单的方法吗?

更新: 这是我的基础 class,它被所有其他 classes.

继承
public class Common
{        
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }        
    [DataType(DataType.DateTime)]
    public DateTime CreatedOn { get; set; } = System.DateTime.Now;
    public string CreatedBy { get; set; }       
    [DataType(DataType.DateTime)]
    public DateTime LastUpdatedOn { get; set; }  = System.DateTime.Now;        
    public string LastUpdatedBy { get; set; }
    public string Remarks { get; set; }
}

public class table1 : Common
{
    //Other Properties...
}

考虑到 DRY,我建议您创建自己的扩展方法,如下所示:

public static class ExtensionMethod
{
    public static void InmutableCollumn<TEntity, TProperty>(this ModelBuilder modelBuilder, Expression<Func<TEntity, TProperty>> propertyExpression) where TEntity : class
    {

        modelBuilder.Entity<TEntity>()
          .Property(propertyExpression)
            .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
    }
}

那么你会称它为:

modelBuilder.InmutableCollumn<UserSetting, Guid>(p => p.Id);

这将使您的代码更易于维护并减少重复性。

你甚至可以让方法接收一个表达式列表,只需要找到一种方法来处理 属性 类型。看看这个草稿:

    public static void InmutableCollumn<TEntity>(this ModelBuilder modelBuilder, params Expression<Func<TEntity, object>>[] propertiesExpression) where TEntity : class
    {
        foreach(var propertyExpression in propertiesExpression)
            modelBuilder.Entity<TEntity>()
                .Property(propertyExpression)
                .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
    }

所以会这样调用:

modelBuilder.InmutableCollumn<UserSetting>(p => p.ID, p => p.CreatedOn);

有很多方法可以做到这一点,最自然的方法是将通用代码移动到 受约束的泛型 class 实现 IEntityTypeConfiguration<TEntity> 中。然后迭代模型实体类型,通过反射实例化配置class并动态调用ModelBuilderApplyConfiguration方法(或使用反射)。

比如配置class:

public class CommonEntityTypeConfiguration<TEntity> : IEntityTypeConfiguration<TEntity>
    where TEntity : Common
{
    public void Configure(EntityTypeBuilder<TEntity> builder)
    {
        builder.Property(p => p.ID)
            .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
        builder.Property(p => p.CreatedOn)
            .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
        builder.Property(p => p.CreatedBy)
            .Metadata.AfterSaveBehavior = PropertySaveBehavior.Ignore;
    }
}

并从内部调用它 OnModelCreating:

var entityTypes = modelBuilder.Model.GetEntityTypes()
    .Where(t => typeof(Common).IsAssignableFrom(t.ClrType));
foreach (var entityType in entityTypes)
{
    var configurationType = typeof(CommonEntityTypeConfiguration<>)
        .MakeGenericType(entityType.ClrType);
    modelBuilder.ApplyConfiguration(
        (dynamic)Activator.CreateInstance(configurationType));
}

这使您可以流畅地配置基础 class 的所有方面,而不仅仅是某些属性的 AfterSaveBehavior