Entity Framework Core动态更新实体时的模型丢失问题
问题解决方案
核心原因分析
出现该问题的本质是:EF Core 默认会缓存模型实例,当调用 ReconfigureModelAsync 触发模型重新构建时,若插件配置的加载逻辑未被重复执行、或插件程序集被GC回收,就会导致新增实体无法被重新加入模型。
具体解决步骤
1. 持久化插件程序集引用,避免被回收
加载插件DLL后,必须将程序集实例存储在全局可访问的静态集合中,防止被垃圾回收器回收:
// 在AddOnService中维护静态集合 public static class AddOnService { public static readonly List<Assembly> LoadedPluginAssemblies = new List<Assembly>(); public static void LoadPlugins(string pluginPath) { var pluginFiles = Directory.GetFiles(pluginPath, "*.dll"); foreach (var file in pluginFiles) { var assembly = Assembly.LoadFrom(file); LoadedPluginAssemblies.Add(assembly); } } }
2. 修改OnModelCreating,确保每次构建模型都加载插件配置
不要仅在初始化时调用一次配置导入,而是在ApplicationDBContext的OnModelCreating方法中,每次模型构建都重新加载所有插件的实体配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // 加载核心应用的实体配置 modelBuilder.ApplyConfigurationsFromAssembly(typeof(ApplicationDBContext).Assembly); // 加载所有插件的实体配置 foreach (var pluginAssembly in AddOnService.LoadedPluginAssemblies) { modelBuilder.ApplyConfigurationsFromAssembly(pluginAssembly); } }
3. 验证插件配置类的可访问性
插件中实现IEntityTypeConfiguration<BitLockerVolumeKeyProtector>的类必须是public修饰符,否则EF Core的ApplyConfigurationsFromAssembly无法扫描到该配置。
4. 手动注册实体配置(自动扫描失效时备选)
若自动扫描插件配置存在问题,可通过反射手动获取并注册所有配置类:
foreach (var pluginAssembly in AddOnService.LoadedPluginAssemblies) { // 获取所有实现IEntityTypeConfiguration的非抽象类 var configTypes = pluginAssembly.GetTypes() .Where(t => !t.IsAbstract && typeof(IEntityTypeConfiguration).IsAssignableFrom(t)); foreach (var configType in configTypes) { dynamic configInstance = Activator.CreateInstance(configType); modelBuilder.ApplyConfiguration(configInstance); } }
5. 自定义模型缓存键,触发插件更新后的模型重建
若插件会动态更新,需自定义模型缓存键,确保插件变化时EF Core自动失效旧模型:
public class PluginModelCacheKeyFactory : IModelCacheKeyFactory { public object Create(DbContext context) { // 生成基于插件程序集哈希的缓存键 var pluginHash = string.Join("-", AddOnService.LoadedPluginAssemblies .Select(a => a.FullName.GetHashCode().ToString())); return (context.GetType(), pluginHash); } }
然后在DbContext服务注册时替换默认的缓存键工厂:
services.AddDbContext<ApplicationDBContext>(options => { options.UseSqlServer(yourConnectionString); options.ReplaceService<IModelCacheKeyFactory, PluginModelCacheKeyFactory>(); });
内容的提问来源于stack exchange,提问作者Régis
相关产品推荐
相关产品推荐

