![](/img/trans.png)
[英]How to filter Bulk register IEntityTypeConfiguration<> by DbContext
[英]Bulk register IEntityTypeConfiguration<> entity framework core
好的,所以我正在使用帶有 dot net core 和 code first migrations 的實體框架。 這本身不是問題,我只是想知道是否有人遇到過更好的方法。
目前我有很多像這樣的實體類型配置
public class ExampleEntityConfiguration : IEntityTypeConfiguration<ExampleEntity>
{
public void Configure(EntityTypeBuilder<ExampleEntity> builder)
{
builder.Property(p => p.Id).ValueGeneratedNever();
// more options here
}
}
我像這樣在我的 dbcontext 中注冊它們
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyConfiguration(new ExampleEntityConfiguration());
// lot's more configurations here
}
有沒有人遇到或知道注冊所有IEntityTypeConfiguration
接口的方法?
看起來很多重復的代碼可以通過獲取配置列表、循環它們並在上下文中應用來解決。 我只是不知道從哪里開始獲取存在於特定命名空間中的IEntityTypeConfiguration
類的列表。
任何幫助/建議都會很棒。
使用 EF Core 2.2+,它變得更加簡單:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
Assembly assemblyWithConfigurations = GetType().Assembly; //get whatever assembly you want
modelBuilder.ApplyConfigurationsFromAssembly(assemblyWithConfigurations);
}
它可以通過這樣的反射來完成:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// get ApplyConfiguration method with reflection
var applyGenericMethod = typeof(ModelBuilder).GetMethod("ApplyConfiguration", BindingFlags.Instance | BindingFlags.Public);
// replace GetExecutingAssembly with assembly where your configurations are if necessary
foreach (var type in Assembly.GetExecutingAssembly().GetTypes()
.Where(c => c.IsClass && !c.IsAbstract && !c.ContainsGenericParameters))
{
// use type.Namespace to filter by namespace if necessary
foreach (var iface in type.GetInterfaces()) {
// if type implements interface IEntityTypeConfiguration<SomeEntity>
if (iface.IsConstructedGenericType && iface.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>)) {
// make concrete ApplyConfiguration<SomeEntity> method
var applyConcreteMethod = applyGenericMethod.MakeGenericMethod(iface.GenericTypeArguments[0]);
// and invoke that with fresh instance of your configuration type
applyConcreteMethod.Invoke(modelBuilder, new object[] {Activator.CreateInstance(type)});
break;
}
}
}
}
@Evk kan 的好作品被進一步封裝在一個可重用的擴展方法中:
public static class ModelBuilderExtensions
{
public static void ApplyAllConfigurationsFromCurrentAssembly(this ModelBuilder modelBuilder, Assembly assembly, string configNamespace = "")
{
var applyGenericMethods = typeof(ModelBuilder).GetMethods( BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy);
var applyGenericApplyConfigurationMethods = applyGenericMethods.Where(m => m.IsGenericMethod && m.Name.Equals("ApplyConfiguration", StringComparison.OrdinalIgnoreCase));
var applyGenericMethod = applyGenericApplyConfigurationMethods.Where(m=>m.GetParameters().FirstOrDefault().ParameterType.Name== "IEntityTypeConfiguration`1").FirstOrDefault();
var applicableTypes = assembly
.GetTypes()
.Where(c => c.IsClass && !c.IsAbstract && !c.ContainsGenericParameters);
if (!string.IsNullOrEmpty(configNamespace))
{
applicableTypes = applicableTypes.Where(c => c.Namespace == configNamespace);
}
foreach (var type in applicableTypes)
{
foreach (var iface in type.GetInterfaces())
{
// if type implements interface IEntityTypeConfiguration<SomeEntity>
if (iface.IsConstructedGenericType && iface.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>))
{
// make concrete ApplyConfiguration<SomeEntity> method
var applyConcreteMethod = applyGenericMethod.MakeGenericMethod(iface.GenericTypeArguments[0]);
// and invoke that with fresh instance of your configuration type
applyConcreteMethod.Invoke(modelBuilder, new object[] { Activator.CreateInstance(type) });
Console.WriteLine("applied model " + type.Name);
break;
}
}
}
}
}
並且可以這樣調用:
public class ApiDbContext : DbContext
{
public DbSet<Customer> Customers { get; set; }
public ApiDbContext(DbContextOptions<ApiDbContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.ApplyAllConfigurationsFromCurrentAssembly("MyRoot.Api.Entities.Configuration");
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
}
}
@Evk 的回答有點過時,不再有效,@paul vanbladl 的回答是有效的,雖然它包含硬編碼的字符串,但我非常討厭。 如果有人分享我的感覺,我想以創建靜態擴展方法的形式提出我的解決方案:
public static ModelBuilder ApplyAllConfigurationsFromAssembly(
this ModelBuilder modelBuilder, Assembly assembly)
{
var applyGenericMethod = typeof(ModelBuilder)
.GetMethods(BindingFlags.Instance | BindingFlags.Public)
.Single(m => m.Name == nameof(ModelBuilder.ApplyConfiguration)
&& m.GetParameters().Count() == 1
&& m.GetParameters().Single().ParameterType.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>));
foreach (var type in assembly.GetTypes()
.Where(c => c.IsClass && !c.IsAbstract && !c.ContainsGenericParameters))
{
foreach (var iface in type.GetInterfaces())
{
if (iface.IsConstructedGenericType && iface.GetGenericTypeDefinition() == typeof(IEntityTypeConfiguration<>))
{
var applyConcreteMethod = applyGenericMethod.MakeGenericMethod(iface.GenericTypeArguments[0]);
applyConcreteMethod.Invoke(modelBuilder, new object[] {Activator.CreateInstance(type)});
break;
}
}
}
}
並且,如果您的配置類與您的 DbContext 存儲在同一個程序集中,您可以按如下方式使用此方法:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyAllConfigurationsFromAssembly(GetType().Assembly);
base.OnModelCreating(modelBuilder);
}
-- 數據庫上下文
protected override void OnModelCreating(ModelBuilder builder)
{
builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
base.OnModelCreating(builder);
}
我真的很喜歡@paul vanbladel 為將代碼移動到擴展方法而提供的答案。 我還需要從其他程序集中調用它,因此我創建了一個枚舉並將適用的類型更改為不同的設置。
IEnumerable<Type> assemblyTypeList;
switch (pAssemblyMethodType)
{
case AssemblyMethodType.CallingAssembly:
assemblyTypeList = Assembly.GetCallingAssembly()
.GetTypes()
.Where(c => c.IsClass
&& !c.IsAbstract
&& !c.ContainsGenericParameters);
break;
case AssemblyMethodType.ExecutingAssembly:
assemblyTypeList = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(c => c.IsClass
&& !c.IsAbstract
&& !c.ContainsGenericParameters);
break;
default:
throw new ArgumentOutOfRangeException(nameof(pAssemblyMethodType), pAssemblyMethodType, null);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.