在foreach循环中应用实体配置

时间:2018-06-05 15:19:08

标签: c# generics entity-framework-core entity-framework-core-2.1

我想知道是否有人可能知道如何动态应用实体配置。我不想重复让我们说一下builder.ApplyConfiguration(new PersonConfiguration());对于我将来/可能拥有的每个实体。

我正在尝试使用以下代码,为了简单起见,我已将所有内容放在一个文件中:

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

2 个答案:

答案 0 :(得分:2)

除了按照另一个答案中的建议创建泛型 BaseEntityConfiguration<TEntity>类之外,还需要通过反射调用泛型 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类中有2个ApplyConfiguration方法重载,这些重载仅因参数类型而不同,因此找到该方法包括所有检查。

答案 1 :(得分:0)

未经测试,但您可以尝试以下操作:

foreach (Type entityType in entityTypes)
{
     Type openConfigType = typeof(BaseEntityConfiguration<>);
     Type genericConfigType = openConfigType.MakeGenericType(entityType);
     builder.ApplyConfiguration(Activator.CreateInstance(genericConfigType));           
}