以编程方式生成EF Core迁移失败:后续迁移创建报错求助
EF Core 后续迁移创建失败问题
开发控制台应用用于为引用程序集生成并应用EF Core Migrations,首次迁移可成功创建,但尝试后续迁移时抛出以下异常:
System.InvalidOperationException: The model must be finalized and its runtime dependencies must be initialized before 'GetRelationalModel' can be used. Ensure that either 'OnModelCreating' has completed or, if using a stand-alone 'ModelBuilder', that 'IModelRuntimeInitializer.Initialize(model.FinalizeModel())' was called. at Microsoft.EntityFrameworkCore.RelationalModelExtensions.GetRelationalModel(IModel model) at Microsoft.EntityFrameworkCore.Migrations.Design.MigrationsScaffolder.ScaffoldMigration(String migrationName, String rootNamespace, String subNamespace, String language)
相关代码
迁移生成核心逻辑(已省略文件写入等无关代码)
var references = new[] { typeof(object).GetTypeInfo().Assembly.Location, typeof(Console).GetTypeInfo().Assembly.Location, typeof(MigrationBuilder).GetTypeInfo().Assembly.Location, typeof(ModelBuilder).GetTypeInfo().Assembly.Location, typeof(Action).GetTypeInfo().Assembly.Location, typeof(Expression<>).GetTypeInfo().Assembly.Location, typeof(System.Runtime.AssemblyTargetedPatchBandAttribute).GetTypeInfo().Assembly.Location, typeof(BinaryExpression).GetTypeInfo().Assembly.Location, AppDomain.CurrentDomain.GetAssemblies().Single(a => a.GetName().Name == "netstandard").Location, Path.Combine(Path.GetDirectoryName(typeof(System.Runtime.GCSettings).GetTypeInfo().Assembly.Location), "System.Runtime.dll"), }.Select(r => MetadataReference.CreateFromFile(r)).ToArray(); var ctxType = dbContext.GetType(); var ctxAssemblyRefPath = ctxType.GetTypeInfo().Assembly.Location; var ctxAssemblyMetaData = MetadataReference.CreateFromFile(ctxAssemblyRefPath); // migrationsDirectory包含已生成的迁移类和模型快照类 var migrationsDirectory = GetMigrationsDirectory(); var assemblyName = Path.GetRandomFileName(); var syntaxTrees = Directory .GetFiles(migrationsDirectory) .Select(File.ReadAllText) .Select(f => CSharpSyntaxTree.ParseText(f)); var compilation = CSharpCompilation.Create( assemblyName, syntaxTrees, references: references.Concat(new[] { ctxAssemblyMetaData }), options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary)); using var ms = new MemoryStream(); compilation.Emit(ms); ms.Seek(0, SeekOrigin.Begin); var assembly = AssemblyLoadContext.Default.LoadFromStream(ms); var prop = ctxType.BaseType?.GetProperty("MigrationAssembly"); prop.SetValue(null, assembly.GetName().FullName); var ctxInstance = Activator.CreateInstance(ctxType) as GwrsDbContext; designTimeServices = new ServiceCollection() .AddSingleton<IOperationReporter>(new OperationReporter(null)) .AddSingleton<MigrationsCodeGeneratorDependencies>() .AddSingleton<ValueConverterSelectorDependencies>() .AddSingleton<IValueConverterSelector, ValueConverterSelector>() .AddSingleton<TypeMappingSourceDependencies>() .AddSingleton<RelationalTypeMappingSourceDependencies>() .AddSingleton<ITypeMappingSource, RelTypeMappingSource>() .AddSingleton<ICSharpHelper, CSharpHelper>() .AddSingleton<AnnotationCodeGeneratorDependencies>() .AddSingleton<IAnnotationCodeGenerator, AnnotationCodeGenerator>() .AddSingleton<CSharpMigrationOperationGeneratorDependencies>() .AddSingleton<ICSharpMigrationOperationGenerator, CSharpMigrationOperationGenerator>() .AddSingleton<CSharpSnapshotGeneratorDependencies>() .AddSingleton<ICSharpSnapshotGenerator, CSharpSnapshotGenerator>() .AddSingleton<CSharpMigrationsGeneratorDependencies>() .AddSingleton<IMigrationsCodeGenerator, CSharpMigrationsGenerator>() .AddSingleton<MigrationsScaffolderDependencies>() .AddSingleton<MigrationsScaffolder>() .AddSingleton<IRegisteredServices, RegisteredServices>() .AddSingleton<IPropertyParameterBindingFactory, PropertyParameterBindingFactory>() .AddSingleton<IParameterBindingFactories, ParameterBindingFactories>() .AddSingleton<IConstructorBindingFactory, ConstructorBindingFactory>() .AddSingleton<RuntimeModelDependencies>() .AddSingleton<IMemberClassifier, MemberClassifier>() .AddSingleton<ModelValidatorDependencies>() .AddSingleton<IModelValidator, ModelValidator>() .AddSingleton<ModelRuntimeInitializerDependencies>() .AddSingleton<IModelRuntimeInitializer, ModelRuntimeInitializer>() .AddSingleton<ISnapshotModelProcessor, SnapshotModelProcessor>() .AddSingleton<MigrationBuilder>() .AddSingleton<IMigrationsCodeGeneratorSelector, MigrationsCodeGeneratorSelector>() .AddSingleton(ctxInstance.GetService<IHistoryRepository>()) .AddSingleton(ctxInstance.GetService<IMigrationsIdGenerator>()) .AddSingleton(ctxInstance.GetService<IMigrationsModelDiffer>()) .AddSingleton(ctxInstance.GetService<IMigrationsAssembly>()) .AddSingleton(ctxInstance.GetService<IDesignTimeModel>().Model) .AddSingleton(ctxInstance.GetService<ICurrentDbContext>()) .AddSingleton(ctxInstance.GetService<IDatabaseProvider>()) .AddSingleton(ctxInstance.GetService<IRelationalTypeMappingSource>()) .AddSingleton(ctxInstance.GetService<IMigrator>()); var serviceProvider = designTimeServices.BuildServiceProvider(); string migrationName = GenerateMigrationName(); var scaffolder = serviceProvider.GetRequiredService<MigrationsScaffolder>(); var migration = scaffolder.ScaffoldMigration(migrationName, GetRootNamespace()); // 文件写入逻辑在此处
测试用DbContext实现
public class DevelopmentContext : DbContext { public static string? MigrationAssembly { get; set; } public DevelopmentContext() { var folder = Environment.SpecialFolder.LocalApplicationData; var path = Environment.GetFolderPath(folder); DbPath = Path.Join(path, "development1.db"); } public string DbPath { get; } public DbSet<Foo> Foos { get; } public DbSet<Bar> Bars { get; } protected override void OnConfiguring(DbContextOptionsBuilder options) { options.UseSqlite($"Data Source={DbPath}", a => { if (MigrationAssembly != null) { a.MigrationsAssembly(MigrationAssembly); } }); } }
内容的提问来源于stack exchange,提问作者Ben
相关产品推荐
相关产品推荐

