При отсутствии пользовательских соглашений вы можете использовать типичный цикл modelBuilder.Model.GetEntityTypes()
, определить типы целевых объектов и вызвать общую конфигурацию.
Идентификация в вашем случае немного сложна из-за базового универсального класса, но выполнимо путем итерации вниз Type.BaseType
и проверки на BaseEntity<>
. Найдя его, вы можете получить общий аргумент T
, который понадобится вам позже.
Если вы не хотите использовать универсальный класс, реализующий IEnityTypeConfiguration<TEntity>
, то идея состоит в том, чтобы поместить реализацию в универсальный ограниченный метод, подобный этому
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();