在 foreach 循环中应用实体配置
Applying entity configurations in a foreach loop
我想知道是否有人知道如何动态应用实体配置。我不想重复让我们说 builder.ApplyConfiguration(new PersonConfiguration());对于我 have/might 将来拥有的每个实体。
我正在尝试使用以下代码,为了简单起见,我将所有内容都放在一个文件中:
namespace WebApplication1.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var entityTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(p => p.GetTypes())
.Where(p => typeof(IEntity).IsAssignableFrom(p) && p != typeof(IEntity));
foreach (var entityType in entityTypes)
{
// this doesn't work
//builder.ApplyConfiguration(new BaseEntityConfiguration<entityType>());
}
// this works, but I don't want to basically repeat it for each entity individually
//builder.ApplyConfiguration(new BaseEntityConfiguration<Person>());
//builder.ApplyConfiguration(new PersonConfiguration());
}
public virtual DbSet<Person> People { get; set; }
}
public interface IEntity
{
int Id { get; set; }
string RowModifyUser { get; set; }
DateTime RowModifyDate { get; set; }
byte[] RowVersion { get; set; }
}
public class Person : IEntity
{
public int Id { get; set; }
public string RowModifyUser { get; set; }
public DateTime RowModifyDate { get; set; }
public byte[] RowVersion { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class BaseEntityConfiguration<TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : class, IEntity
{
public void Configure(EntityTypeBuilder<TEntity> builder)
{
builder.HasKey(m => m.Id);
builder.Property(m => m.RowModifyDate).IsRequired();
builder.Property(m => m.RowModifyUser).IsRequired();
builder.Property(m => m.RowVersion).IsRequired().IsConcurrencyToken();
}
}
public class PersonConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.Property(m => m.FirstName).IsRequired();
builder.Property(m => m.LastName).IsRequired();
}
}
}
未经测试,但您可以尝试以下操作:
foreach (Type entityType in entityTypes)
{
Type openConfigType = typeof(BaseEntityConfiguration<>);
Type genericConfigType = openConfigType.MakeGenericType(entityType);
builder.ApplyConfiguration(Activator.CreateInstance(genericConfigType));
}
除了按照另一个答案中的建议创建 generic BaseEntityConfiguration<TEntity>
class 之外,您还需要调用 generic ModelBuilder.ApplyConfiguration<TEntity>(IEntityTypeConfiguration<TEntity> configuration)
通过反射的方法。
类似这样的东西(需要 using System.Reflection;
):
// Can be moved to a static readonly field of the class
var applyConfigurationMethodDefinition = typeof(ModelBuilder)
.GetTypeInfo()
.DeclaredMethods
.Single(m => m.Name == "ApplyConfiguration" &&
m.IsGenericMethodDefinition &&
m.GetParameters().Length == 1 &&
m.GetParameters()[0].ParameterType.IsGenericType &&
m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>));
foreach (var entityType in entityTypes)
{
var configurationType = typeof(BaseEntityConfiguration<>).MakeGenericType(entityType);
var configuration = Activator.CreateIntance(configurationType);
var applyConfigurationMethod = applyConfigurationMethodDefinition.MakeGenericMethod(entityType);
applyConfigurationMethod.Invoke(builder, new object[] { configuration });
}
请注意,在 EF Core 2.1 ModelBuilder
class 中有 2 个 ApplyConfiguration
方法重载,它们仅在参数类型上有所不同,这就是查找方法包括所有检查的原因。
我想知道是否有人知道如何动态应用实体配置。我不想重复让我们说 builder.ApplyConfiguration(new PersonConfiguration());对于我 have/might 将来拥有的每个实体。
我正在尝试使用以下代码,为了简单起见,我将所有内容都放在一个文件中:
namespace WebApplication1.Data
{
public class ApplicationDbContext : IdentityDbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
var entityTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(p => p.GetTypes())
.Where(p => typeof(IEntity).IsAssignableFrom(p) && p != typeof(IEntity));
foreach (var entityType in entityTypes)
{
// this doesn't work
//builder.ApplyConfiguration(new BaseEntityConfiguration<entityType>());
}
// this works, but I don't want to basically repeat it for each entity individually
//builder.ApplyConfiguration(new BaseEntityConfiguration<Person>());
//builder.ApplyConfiguration(new PersonConfiguration());
}
public virtual DbSet<Person> People { get; set; }
}
public interface IEntity
{
int Id { get; set; }
string RowModifyUser { get; set; }
DateTime RowModifyDate { get; set; }
byte[] RowVersion { get; set; }
}
public class Person : IEntity
{
public int Id { get; set; }
public string RowModifyUser { get; set; }
public DateTime RowModifyDate { get; set; }
public byte[] RowVersion { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class BaseEntityConfiguration<TEntity> : IEntityTypeConfiguration<TEntity> where TEntity : class, IEntity
{
public void Configure(EntityTypeBuilder<TEntity> builder)
{
builder.HasKey(m => m.Id);
builder.Property(m => m.RowModifyDate).IsRequired();
builder.Property(m => m.RowModifyUser).IsRequired();
builder.Property(m => m.RowVersion).IsRequired().IsConcurrencyToken();
}
}
public class PersonConfiguration : IEntityTypeConfiguration<Person>
{
public void Configure(EntityTypeBuilder<Person> builder)
{
builder.Property(m => m.FirstName).IsRequired();
builder.Property(m => m.LastName).IsRequired();
}
}
}
未经测试,但您可以尝试以下操作:
foreach (Type entityType in entityTypes)
{
Type openConfigType = typeof(BaseEntityConfiguration<>);
Type genericConfigType = openConfigType.MakeGenericType(entityType);
builder.ApplyConfiguration(Activator.CreateInstance(genericConfigType));
}
除了按照另一个答案中的建议创建 generic BaseEntityConfiguration<TEntity>
class 之外,您还需要调用 generic ModelBuilder.ApplyConfiguration<TEntity>(IEntityTypeConfiguration<TEntity> configuration)
通过反射的方法。
类似这样的东西(需要 using System.Reflection;
):
// Can be moved to a static readonly field of the class
var applyConfigurationMethodDefinition = typeof(ModelBuilder)
.GetTypeInfo()
.DeclaredMethods
.Single(m => m.Name == "ApplyConfiguration" &&
m.IsGenericMethodDefinition &&
m.GetParameters().Length == 1 &&
m.GetParameters()[0].ParameterType.IsGenericType &&
m.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>));
foreach (var entityType in entityTypes)
{
var configurationType = typeof(BaseEntityConfiguration<>).MakeGenericType(entityType);
var configuration = Activator.CreateIntance(configurationType);
var applyConfigurationMethod = applyConfigurationMethodDefinition.MakeGenericMethod(entityType);
applyConfigurationMethod.Invoke(builder, new object[] { configuration });
}
请注意,在 EF Core 2.1 ModelBuilder
class 中有 2 个 ApplyConfiguration
方法重载,它们仅在参数类型上有所不同,这就是查找方法包括所有检查的原因。