如何在 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并动态调用ModelBuilder
的ApplyConfiguration
方法(或使用反射)。
比如配置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
。
我在 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并动态调用ModelBuilder
的ApplyConfiguration
方法(或使用反射)。
比如配置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
。