繁体   English   中英

如何将通用配置应用于 ef core 中的所有实体

[英]how to apply common configuration to all entities in ef core

我的应用程序中有从使用 ef 核心代码优先方法的基本实体派生的实体。

基地 class

public abstract class BaseEntity<T> : IEntity<T>
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public T Id { get; set; }

    object IEntity.Id { get { return Id; } set { } }

    private DateTime? createdOn;
    [DataType(DataType.DateTime)]
    public DateTime CreatedOn { get => createdOn ?? DateTime.Now; set => createdOn = value; }

    [DataType(DataType.DateTime)]
    public DateTime? ModifiedOn { get; set; }

    public bool IsDeleted { get; set; }
    // Auto increment for all entities.
    public int OrderId { get; set; }
}

和一个实体

public class UserEntity : BaseEntity<int>
{
    public string EmployeeId { get; set; }
    public string FullName { get; set; }
    public string Email { get; set; }
}

我可以为每个实体OnModelCreating中的属性OrderId上应用.ValueGeneratedOnAdd()方法,但是,有没有一种方法可以对所有实体应用通用规则而无需自己重复?

由于缺少自定义约定,您可以使用典型的modelBuilder.Model.GetEntityTypes()循环,标识目标实体类型并调用常用配置。

由于基类泛型类,在您的情况下标识有点复杂,但可以通过迭代Type.BaseType并检查BaseEntity<> 找到后,您可以检索以后需要的通用参数T

如果你不想使用实现IEnityTypeConfiguration<TEntity> 泛型类,那么想法是将实现放在这样的通用约束方法中

static void Configure<TEntity, T>(ModelBuilder modelBuilder)
    where TEntity : BaseEntity<T>
{
    modelBuilder.Entity<TEntity>(builder =>
    {
        builder.Property(e => e.OrderId).ValueGeneratedOnAdd();
    });
}

将实际实体类型TEntity传递给modelBuilder.Enity方法至关重要,因为否则EF Core会将您传递的任何内容视为实体类型并配置TPH继承。

调用方法需要反射 - 使用MakeGenericMethod然后Invoke查找泛型方法定义。

以下是封装在静态类中的所有内容:

public static class BaseEntityConfiguration
{
    static void Configure<TEntity, T>(ModelBuilder modelBuilder)
        where TEntity : BaseEntity<T>
    {
        modelBuilder.Entity<TEntity>(builder =>
        {
            builder.Property(e => e.OrderId).ValueGeneratedOnAdd();
        });
    }

    public static ModelBuilder ApplyBaseEntityConfiguration(this ModelBuilder modelBuilder)
    {
        var method = typeof(BaseEntityConfiguration).GetTypeInfo().DeclaredMethods
            .Single(m => m.Name == nameof(Configure));
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            if (entityType.ClrType.IsBaseEntity(out var T))
                method.MakeGenericMethod(entityType.ClrType, T).Invoke(null, new[] { modelBuilder });
        }
        return modelBuilder;
    }

    static bool IsBaseEntity(this Type type, out Type T)
    {
        for (var baseType = type.BaseType; baseType != null; baseType = baseType.BaseType)
        {
            if (baseType.IsGenericType && baseType.GetGenericTypeDefinition() == typeof(BaseEntity<>))
            {
                T = baseType.GetGenericArguments()[0];
                return true;
            }
        }
        T = null;
        return false;
    }
}

现在您只需要从OnModelCreating覆盖中调用它:

modelBuilder.ApplyBaseEntityConfiguration();

在EF6中,您可以使用:

modelBuilder.Properties<int>().Where(p=>p.Name == "OrderId").Configure(c => c.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity));
foreach (var item in modelBuilder.Model.GetEntityTypes())
{
    item.FindProperty("CreatedOn")?.SetDefaultValueSql("GETDATE()");
    item.FindProperty("ModifiedOn")?.SetDefaultValueSql("GETDATE()");
    item.FindProperty("AAStatus")?.SetDefaultValue("Alive");
}

我研究并找到了这个线程,阅读后我的解决方案是

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM