In my EF core project I have a few entities that inherit from a base class 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; }
}
I want to set some specific properties with default value for every entity that inherits from DBEntity. Currently I'm using this code:
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);
}
}
This works fine but I don't want to specify property names using string constants (bad for refactoring etc.).
Is there a way to loop through entities that inherit from DBEntity and use property expression to configure default values like this:
foreach (var entity in entities)
{
entity
.Property(k => k.CreatedOn)
.HasDefaultValueSql("GETDATE()");
// ....
}
Important constraint: I cannot directly call modelBuilder.Entity().Property(k => k.CreatedOn) because it will mess up all tables.
解决方案
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(ModelBuilder modelBuilder)
where TEntity : DBEntity
{
var entity = modelBuilder.Entity();
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);