【问题标题】:how to apply common configuration to all entities in ef core如何将通用配置应用于 ef core 中的所有实体
【发布时间】:2018-11-13 07:05:22
【问题描述】:

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

基类

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() 方法对于每个实体 但是,有没有办法为所有实体应用一般规则而无需自己重复? p>

【问题讨论】:

  • 你不能在OrderId 上也使用[DatabaseGenerated(DatabaseGeneratedOption.Identity)] 吗?
  • 已经有一个带有标识选项的主键列。所以不允许再有这个属性了。
  • 与问题无关,但IEntity 知道IdT 所以IEntity.Id 不需要返回object
  • @sellotape 请参考此link 并查看实施段落了解详细信息..
  • @ibubi - 很公平;我应该意识到这是IEntity.Id,而不是IEntity&lt;T&gt;.Id...

标签: c# entity-framework-core


【解决方案1】:

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

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

如果你不想使用实现IEnityTypeConfiguration&lt;TEntity&gt;generic类,那么想法就是把实现放在generic constrained这样的方法中

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();

【讨论】:

  • 感谢您的详细回答。
  • @Ivan Stoev,它不适用于 EF Core 3.0。注意:我的 BaseEnity 不是通用的。
  • @TanvirArjel 如果您的基本实体不是通用的,那么它应该更简单。从Configure 方法(例如static void Configure&lt;TEntity&gt;(ModelBuilder modelBuilder) where TEntity : BaseEntity)和MakeGenericMethod 中删除T。也不需要IsBaseEntity 方法,例如使用if (entityType.ClrType.IsSubclassOf(typeof(BaseEntity)) 标准。
  • @IvanStoev 那是因为我的实体不继承自 BaseEntity(因为它们独立于 EF)。所以我需要像在 EF6 中一样从 modelBuilder 访问所有属性(即:modelBuilder.Properties&lt;string&gt;().Configure(x =&gt; x.HasColumnType("VARCHAR2"));
【解决方案2】:

在 EF6 中你可以使用:

modelBuilder.Properties<int>().Where(p=>p.Name == "OrderId").Configure(c => c.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity));

【讨论】:

    猜你喜欢
    • 2020-05-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-15
    • 2022-01-25
    • 2021-10-28
    相关资源
    最近更新 更多