EF 中的通用实体映射
Generic Entity mapping in EF
我想制作一个将所有实体映射到 dbContext 和 EF 的通用实体映射器。目前,在我执行 Add-Migration init
之后,我收到一个错误:
Cannot create an instance of Models.DataMapping.EntityMapper`1[TEntity] because Type.ContainsGenericParameters is true.
我不明白这个错误的确切含义,以及为什么如果类型 ContainsGenericParameters
为真,它会导致崩溃。有什么问题吗?我该如何解决?
这是我的代码:
namespace Models.DataMapping
{
public interface IEntityMapper
{
void Map(ModelBuilder modelBuilder);
}
}
namespace Models.DataMapping
{
public abstract class EntityMapper<TEntity> :
IEntityMapper where TEntity : class
{
public void Map(ModelBuilder modelBuilder)
{
EntityTypeBuilder<TEntity> entityTypeBuilder = modelBuilder.Entity<TEntity>();
MapEntity(entityTypeBuilder);
}
protected virtual void MapEntity(EntityTypeBuilder<TEntity> entityTypeBuilder)
{
}
}
}
namespace Models.DataMapping
{
public static class EntityMappersProvider
{
public static IReadOnlyCollection<IEntityMapper> GetLocalEntityMappers() {
return Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => typeof(IEntityMapper).IsAssignableFrom(t) && t.IsClass)
.Select(t => (IEntityMapper)Activator.CreateInstance(t))
.ToArray();
}
}
}
在 dbContext 中包含提供者。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
IReadOnlyCollection<IEntityMapper> entityMappers = EntityMappersProvider.GetLocalEntityMappers();
foreach (IEntityMapper mapper in entityMappers) {
mapper.Map(modelBuilder);
}
}
实体关系实现示例。
namespace Models.DataMapping.EntitiesMapping
{
public class CourseMapper : EntityMapper<Course>
{
protected override void MapEntity(EntityTypeBuilder<Course> entityTypeBuilder)
{
entityTypeBuilder.ToTable("Courses");
entityTypeBuilder.HasKey(a => a.Id);
//....
}
}
}
我还注意到,如果我在 EntityMapper
中删除 abstract
关键字并在 EntityMappersProvided
中添加 t.IsAbstract
,则会创建空迁移..
对我来说,您似乎正在尝试重新发明 IEntityTypeConfiguration
,它允许将实体配置代码移动到单独的 类 :
public class BlogEntityTypeConfiguration : IEntityTypeConfiguration<Blog>
{
public void Configure(EntityTypeBuilder<Blog> builder)
{
builder
.Property(b => b.Url)
.IsRequired();
}
}
并提供方便的方法在程序集中查找所有此类配置,自 EF Core 2.2:
起可用
modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);
至于你的错误 - 它发生是因为你的代码试图用 Activator.CreateInstance
:
实例化一个开放的泛型类型 (EntityMapper<TEntity>
)
public class OpenGeneric<T>{}
Activator.CreateInstance(typeof(OpenGeneric<>)); // throws Cannot create an instance of Generic`1[T] because Type.ContainsGenericParameters is true.
因此您需要将其过滤掉,例如在 Where
子句中添加 && !t.IsAbstract && ! t.ContainsGenericParameters
。
我想制作一个将所有实体映射到 dbContext 和 EF 的通用实体映射器。目前,在我执行 Add-Migration init
之后,我收到一个错误:
Cannot create an instance of Models.DataMapping.EntityMapper`1[TEntity] because Type.ContainsGenericParameters is true.
我不明白这个错误的确切含义,以及为什么如果类型 ContainsGenericParameters
为真,它会导致崩溃。有什么问题吗?我该如何解决?
这是我的代码:
namespace Models.DataMapping
{
public interface IEntityMapper
{
void Map(ModelBuilder modelBuilder);
}
}
namespace Models.DataMapping
{
public abstract class EntityMapper<TEntity> :
IEntityMapper where TEntity : class
{
public void Map(ModelBuilder modelBuilder)
{
EntityTypeBuilder<TEntity> entityTypeBuilder = modelBuilder.Entity<TEntity>();
MapEntity(entityTypeBuilder);
}
protected virtual void MapEntity(EntityTypeBuilder<TEntity> entityTypeBuilder)
{
}
}
}
namespace Models.DataMapping
{
public static class EntityMappersProvider
{
public static IReadOnlyCollection<IEntityMapper> GetLocalEntityMappers() {
return Assembly.GetExecutingAssembly()
.GetTypes()
.Where(t => typeof(IEntityMapper).IsAssignableFrom(t) && t.IsClass)
.Select(t => (IEntityMapper)Activator.CreateInstance(t))
.ToArray();
}
}
}
在 dbContext 中包含提供者。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
IReadOnlyCollection<IEntityMapper> entityMappers = EntityMappersProvider.GetLocalEntityMappers();
foreach (IEntityMapper mapper in entityMappers) {
mapper.Map(modelBuilder);
}
}
实体关系实现示例。
namespace Models.DataMapping.EntitiesMapping
{
public class CourseMapper : EntityMapper<Course>
{
protected override void MapEntity(EntityTypeBuilder<Course> entityTypeBuilder)
{
entityTypeBuilder.ToTable("Courses");
entityTypeBuilder.HasKey(a => a.Id);
//....
}
}
}
我还注意到,如果我在 EntityMapper
中删除 abstract
关键字并在 EntityMappersProvided
中添加 t.IsAbstract
,则会创建空迁移..
对我来说,您似乎正在尝试重新发明 IEntityTypeConfiguration
,它允许将实体配置代码移动到单独的 类 :
public class BlogEntityTypeConfiguration : IEntityTypeConfiguration<Blog>
{
public void Configure(EntityTypeBuilder<Blog> builder)
{
builder
.Property(b => b.Url)
.IsRequired();
}
}
并提供方便的方法在程序集中查找所有此类配置,自 EF Core 2.2:
起可用modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);
至于你的错误 - 它发生是因为你的代码试图用 Activator.CreateInstance
:
EntityMapper<TEntity>
)
public class OpenGeneric<T>{}
Activator.CreateInstance(typeof(OpenGeneric<>)); // throws Cannot create an instance of Generic`1[T] because Type.ContainsGenericParameters is true.
因此您需要将其过滤掉,例如在 Where
子句中添加 && !t.IsAbstract && ! t.ContainsGenericParameters
。