GetEntityTypes: configure entity properties using the generic version of .Property<TEntity> in EF Core

大憨熊 提交于 2019-11-29 08:13:24

As pointed out in the comments, you can simply replace the string constants with nameof(DBEntity.CreatedOn) etc.

But if you want to work with typed accessors, you can move the base entity configuration code to a generic method (with the generic argument being the actual entity type) and call it via reflection.

For instance, add the following to your DbContext derived class:

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

}

and then use something like this:

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

What about, in your context, adding something like this

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

You have the drawback to not enforcing those default values at db level (at this point you are db agnostic) but stil able to refactor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!