简体   繁体   English

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

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

I have entities derived from a base entity in my application which uses ef core code-first approach.我的应用程序中有从使用 ef 核心代码优先方法的基本实体派生的实体。

Base class基地 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; }
}

And an entity和一个实体

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

I can apply the .ValueGeneratedOnAdd() method on property OrderId in OnModelCreating for each entity however, is there a way to apply a general rule for all entities without repeatig yourself?我可以为每个实体OnModelCreating中的属性OrderId上应用.ValueGeneratedOnAdd()方法,但是,有没有一种方法可以对所有实体应用通用规则而无需自己重复?

With the lack of custom conventions, you could use the typical modelBuilder.Model.GetEntityTypes() loop, identify the target entity types and invoke common configuration. 由于缺少自定义约定,您可以使用典型的modelBuilder.Model.GetEntityTypes()循环,标识目标实体类型并调用常用配置。

Identification in your case is a bit complicated because of the base generic class, but doable by iterating down Type.BaseType and check for BaseEntity<> . 由于基类泛型类,在您的情况下标识有点复杂,但可以通过迭代Type.BaseType并检查BaseEntity<> Once you find it, you can retrieve the generic argument T which you'll need later. 找到后,您可以检索以后需要的通用参数T

If you don't want to use generic class implementing IEnityTypeConfiguration<TEntity> , then the idea is to put the implementation in generic constrained method like this 如果你不想使用实现IEnityTypeConfiguration<TEntity> 泛型类,那么想法是将实现放在这样的通用约束方法中

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

Passing the actual entity type TEntity to modelBuilder.Enity method is crucial, because otherwise EF Core will consider whatever you pass to be an entity type and configure TPH inheritance. 将实际实体类型TEntity传递给modelBuilder.Enity方法至关重要,因为否则EF Core会将您传递的任何内容视为实体类型并配置TPH继承。

Calling the method requires reflection - finding the generic method definition, using MakeGenericMethod and then Invoke . 调用方法需要反射 - 使用MakeGenericMethod然后Invoke查找泛型方法定义。

Here is all that encapsulated in a static class: 以下是封装在静态类中的所有内容:

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;
    }
}

Now all you need is to call it from inside your OnModelCreating override: 现在您只需要从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");
}

i researched and found this thread, my solution after reading it is我研究并找到了这个线程,阅读后我的解决方案是

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

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