【问题标题】:GetEntityTypes: configure entity properties using the generic version of .Property<TEntity> in EF CoreGetEntityTypes:在 EF Core 中使用 .Property<TEntity> 的通用版本配置实体属性
【发布时间】:2018-09-15 12:29:59
【问题描述】:

在我的 EF 核心项目中,我有一些从基类 DBEntity 继承的实体:

public abstract class DBEntity
{
    public int Id { get; set; }

    public DateTime CreatedOn { get; set; }

    public DateTime UpdatedOn { get; set; }

    public EntityStatus EntityStatus { get; set; }
}

我想为从 DBEntity 继承的每个实体设置一些具有默认值的特定属性。目前我正在使用此代码:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {

        var entities = modelBuilder.Model
            .GetEntityTypes()
            .Where(w => w.ClrType.IsSubclassOf(typeof(DBEntity)))
            .Select(p => modelBuilder.Entity(p.ClrType));

        foreach (var entity in entities)
        {

            entity
                .Property("CreatedOn")
                .HasDefaultValueSql("GETDATE()");

            entity
                .Property("UpdatedOn")
                .HasComputedColumnSql("GETDATE()");

            entity
                .Property("EntityStatus")
                .HasDefaultValue(EntityStatus.Created);

        }
    }

这很好用,但我不想使用字符串常量指定属性名称(不利于重构等)。

有没有办法遍历继承自 DBEntity 的实体并使用属性表达式来配​​置默认值,如下所示:

foreach (var entity in entities)
{
    entity
      .Property(k => k.CreatedOn)
      .HasDefaultValueSql("GETDATE()");

// ....

}

重要约束:我不能直接调用modelBuilder.Entity().Property(k => k.CreatedOn),因为它会弄乱所有的表。

【问题讨论】:

  • 有可能,但更简单的是使用nameof而不是字符串常量。
  • @IvanStoev nameof(DBEntity.CreatedOn) 有效!另一种方法是什么?
  • 创建一个泛型方法并通过反射调用它。

标签: c# entity-framework entity-framework-core ef-core-2.0


【解决方案1】:

正如 cmets 中所指出的,您可以简单地将字符串常量替换为 nameof(DBEntity.CreatedOn) 等。

但是,如果您想使用类型化访问器,您可以将基本实体配置代码移动到 generic 方法(泛型参数是实际的实体类型)并通过反射调用它。

例如,将以下内容添加到您的 DbContext 派生类中:

static void ConfigureDBEntity<TEntity>(ModelBuilder modelBuilder)
    where TEntity : DBEntity
{
    var entity = modelBuilder.Entity<TEntity>();

    entity
        .Property(e => e.CreatedOn)
        .HasDefaultValueSql("GETDATE()");

    entity
        .Property(e => e.UpdatedOn)
        .HasComputedColumnSql("GETDATE()");

    entity
        .Property(e => e.EntityStatus)
        .HasDefaultValue(EntityStatus.Created);

}

然后使用这样的东西:

var entityTypes = modelBuilder.Model
        .GetEntityTypes()
        .Where(t => t.ClrType.IsSubclassOf(typeof(DBEntity)));

var configureMethod = GetType().GetTypeInfo().DeclaredMethods.Single(m => m.Name == nameof(ConfigureDBEntity));
var args = new object[] { modelBuilder };
foreach (var entityType in entityTypes)
    configureMethod.MakeGenericMethod(entityType.ClrType).Invoke(null, args);

【讨论】:

  • 我正在尝试实施您建议的解决方案,但我的基本实体采用通用类型参数 (BaseEntity)。因此,当我将 typeof(BaseEntity) 传递给 IsSubclassOf() 时,会出现错误:Error CS0305 Using the generic type 'BaseEntity&lt;T&gt;' requires 1 type arguments。在这种情况下,我不确定如何使用类型参数传递类的类型。任何帮助都感激不尽。谢谢。
  • @SuhaibSyed 这里stackoverflow.com/questions/53275567/… 是一个例子——IsBaseEntity 方法,如果你不需要它,你可以去掉out T 参数。
【解决方案2】:

在你的上下文中,添加这样的东西怎么样

    public override int SaveChanges()
    {
        AddTimestamps();
        return base.SaveChanges();
    }

    public override async Task<int> SaveChangesAsync(bool acceptAllChangesOnSuccess, CancellationToken cancellationToken = default(CancellationToken))
    {
        AddTimestamps();
        return await base.SaveChangesAsync(acceptAllChangesOnSuccess, cancellationToken);
    }

    private void AddTimestamps()
    {
        var entities = ChangeTracker.Entries()
            .Where(x => (x.Entity is DBEntity) && (x.State == EntityState.Added || x.State == EntityState.Modified));

        var now = DateTime.UtcNow; // current datetime

        foreach (var entity in entities)
        {
            if (entity.State == EntityState.Added)
            {
                ((DBEntity)entity.Entity).CreatedOn = now;
                ((DBEntity)entity.Entity).EntityStatus = EntityStatus.Created;
            }
            ((DBEntity)entity.Entity).UpdatedOn= now;
        }
    }

你的缺点是没有在 db 级别强制执行这些默认值(此时你是 db 不可知论者)但仍然可以重构

【讨论】:

    猜你喜欢
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多