假设我有一些界面,例如:
public interface ISoftDeletable
{
bool IsActive { get; set }
}
我有很多实现它的实体:
public class Entity1 : ISoftDeletable
{
public int Id { get; set }
public bool IsActive { get; set; }
}
public class Entity2 : ISoftDeletable
{
public int Id { get; set }
public bool IsActive { get; set; }
}
在OnModelCreating
中:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Entity1>().Property(e => e.IsActive).HasDefaultValue(true);
modelBuilder.Entity<Entity2>().Property(e => e.IsActive).HasDefaultValue(true);
}
是否有任何方法可以重构它,所以我可以为实现HasDefaultValue
的所有实体设置ISoftDeletable
而不是像上面那样做?
我可能可以为每个实体使用IsActive = true
使用默认构造函数来解决这种特定情况,甚至可以创建一个基本抽象类,但是我不太喜欢。
相似的问题:Ef core fluent api set all column types of interface
还有更好的方法吗?
答案 0 :(得分:2)
我在这里找到了一些答案:GetEntityTypes: configure entity properties using the generic version of .Property<TEntity> in EF Core
除了上面的注释之外,还有一种方法可以不对每个实体调用它。如我的问题下Erndob的评论所述,这可能可以重构为某种扩展方法。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
if (typeof(ISoftDeletable).IsAssignableFrom(entityType.ClrType))
{
modelBuilder.Entity(entityType.ClrType).Property<bool>(nameof(ISoftDeletable.IsActive)).HasDefaultValue(true);
}
}
}
解决方案是使用ModelBuilder.Model.GetEntityTypes()
并查找可从ISoftDeletable
分配的实体类型。
我认为,这比手动配置它甚至创建抽象IEntityTypeConfiguration<>
类要好得多,因为您不必记住对所有ISoftDeletable
类都使用它。
外观更简洁
public static class ModelBuilderExtensions
{
public static ModelBuilder EntitiesOfType<T>(this ModelBuilder modelBuilder,
Action<EntityTypeBuilder> buildAction) where T : class
{
return modelBuilder.EntitiesOfType(typeof(T), buildAction);
}
public static ModelBuilder EntitiesOfType(this ModelBuilder modelBuilder, Type type,
Action<EntityTypeBuilder> buildAction)
{
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
if (type.IsAssignableFrom(entityType.ClrType))
buildAction(modelBuilder.Entity(entityType.ClrType));
return modelBuilder;
}
}
还有OnModelCreating
:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.EntitiesOfType<ISoftDeletable>(builder =>
{
builder.Property<bool>(nameof(ISoftDeletable.IsActive)).HasDefaultValue(true);
// query filters :)
var param = Expression.Parameter(builder.Metadata.ClrType, "p");
var body = Expression.Equal(Expression.Property(param, nameof(ISoftDeletable.IsActive)), Expression.Constant(true));
builder.HasQueryFilter(Expression.Lambda(body, param));
});
}
答案 1 :(得分:0)
我想做类似的事情,但是使用app.json
界面保存我的通用配置。我最终不得不使用反射,但是有效:
IEntityTypeConfiguration
:
Interface
public interface IHasDisplayId
{
Guid DisplayId { get; }
}
:
EntityTypeConfig
public class HasDisplayIdEntityTypeConfiguration<T> : IEntityTypeConfiguration<T> where T : class, IHasDisplayId
{
public void Configure(EntityTypeBuilder<T> builder)
{
builder.Property(e => e.DisplayId).IsRequired();
builder.HasIndex(e => e.DisplayId);
}
}
:
Extension method
public static ModelBuilder ApplyConfiguration<T>(this ModelBuilder modelBuilder, Type configurationType, Type entityType)
{
if (typeof(T).IsAssignableFrom(entityType))
{
// Build IEntityTypeConfiguration type with generic type parameter
var configurationGenericType = configurationType.MakeGenericType(entityType);
// Create an instance of the IEntityTypeConfiguration implementation
var configuration = Activator.CreateInstance(configurationGenericType);
// Get the ApplyConfiguration method of ModelBuilder via reflection
var applyEntityConfigurationMethod = typeof(ModelBuilder)
.GetMethods()
.Single(e => e.Name == nameof(ModelBuilder.ApplyConfiguration)
&& e.ContainsGenericParameters
&& e.GetParameters().SingleOrDefault()?.ParameterType.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>));
// Create a generic ApplyConfiguration method with our entity type
var target = applyEntityConfigurationMethod.MakeGenericMethod(entityType);
// Invoke ApplyConfiguration, passing our IEntityTypeConfiguration instance
target.Invoke(modelBuilder, new[] { configuration });
}
return modelBuilder;
}
:
Usage