如何将通用配置应用于 ef core 中的所有实体 [英] how to apply common configuration to all entities in ef core

查看:15
本文介绍了如何将通用配置应用于 ef core 中的所有实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用程序中的基础实体派生自使用 ef 核心代码优先方法的实体.

I have entities derived from a base entity in my application which uses ef core code-first approach.

基类

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

我可以将 .ValueGeneratedOnAdd() 方法应用于 OnModelCreating 每个实体 中的属性 OrderId ,但是,有没有一种方法可以在不重复自己的情况下对所有实体应用一般规则?

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?

推荐答案

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

With the lack of custom conventions, you could use the typical modelBuilder.Model.GetEntityTypes() loop, identify the target entity types and invoke common configuration.

由于基础 generic 类,在您的情况下的识别有点复杂,但可以通过向下迭代 Type.BaseType 并检查 BaseEntity<> 来实现..一旦找到它,您就可以检索稍后需要的通用参数 T.

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<>. Once you find it, you can retrieve the generic argument T which you'll need later.

如果你不想使用generic类实现IEnityTypeConfiguration,那么想法是把实现放在generic constrained 这样的方法

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

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 继承.

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.

调用方法需要反射——找到泛型方法定义,使用MakeGenericMethod然后Invoke.

Calling the method requires reflection - finding the generic method definition, using MakeGenericMethod and then 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;
    }
}

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

Now all you need is to call it from inside your OnModelCreating override:

modelBuilder.ApplyBaseEntityConfiguration();

这篇关于如何将通用配置应用于 ef core 中的所有实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆