实现接口的实体的通用配置

Kon*_*rad 3 c# entity-framework-core

假设我有一些界面,例如:

public interface ISoftDeletable
{
    bool IsActive { get; set }
}
Run Code Online (Sandbox Code Playgroud)

我有很多实体实现了它:

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; }
}
Run Code Online (Sandbox Code Playgroud)

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);
}
Run Code Online (Sandbox Code Playgroud)

有什么方法可以重构它,以便我可以HasDefaultValue为所有实体实现设置,ISoftDeletable而不是像上面那样做?

我可能可以使用每个实体的默认构造函数解决这个特定情况,IsActive = true甚至创建一个基本抽象类,但我不太喜欢它。

类似问题:Ef core fluent api set all column types of interface

有没有更好的办法?

Kon*_*rad 12

我在这里找到了一些答案: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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

解决方案是使用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;
    }
}
Run Code Online (Sandbox Code Playgroud)

并且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));
    });
}
Run Code Online (Sandbox Code Playgroud)