EF Core 9跨多项目预编译模型/查询的实现难题
我的应用基于EF Core构建,数据库功能拆分到5个独立项目:
- 数据模型项目:存放所有数据库模型对象
- DbContext项目:包含DbContext及模型配置
- Migrations项目:管理数据库迁移
- Factory项目:负责实例化带正确提供程序、文件IO和迁移选项的DbContext
- 应用服务项目:从Factory获取DbContext实例,提供查询结果方法给应用
随着EF Core 9发布,我想通过Native AOT预编译模型和查询提升Android端性能,但不确定操作位置和工具协作方式。
最初尝试在应用服务项目中预编译,但因大量命名空间缺失失败,而且服务项目不实例化DbContext,无法指定要使用的编译模型。
我认为不能在DbContext项目中预编译,因为它不能引用Migrations项目(会造成循环引用),于是新建了一个包含IDesignContextFactory的项目来存放编译模型,但运行CLI工具生成模型时触发了空引用异常(NRE),错误信息如下:
dotnet ef dbcontext optimize --configuration Release --context FieldStorageContext --nativeaot Build started... Build succeeded. NativeAOT support is experimental and can change in the future. Your target project 'FieldStorageCompiledModel' doesn't match the assembly containing 'FieldStorageContext' - 'FieldStorage'. This is not recommended as it will cause the compiled model to not be discovered automatically. Consider changing your target project to the DbContext project by using the Package Manager Console's Default project drop-down list, by executing "dotnet ef" from the directory containing the DbContext project or by supplying it with the '--project' option.
异常堆栈信息:
System.NullReferenceException: Object reference not set to an instance of an object.
at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.GetUnsafeAccessorName(MemberInfo member)
at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.RegisterPrivateAccessor(IPropertyBase property, Boolean forMaterialization, Boolean forSet, String namespace, BidirectionalDictionary2 unsafeAccessorClassNames, Dictionary2 unsafeAccessorTypes, Dictionary2& memberAccessReplacements) at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.RegisterPrivateAccessors(IPropertyBase property, String namespace, BidirectionalDictionary2 unsafeAccessorClassNames, Dictionary2 unsafeAccessorTypes, Dictionary2 memberAccessReplacements)
at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CSharpRuntimeModelCodeGenerator.GenerateModel(IModel model, CompiledModelCodeGenerationOptions options)
at Microsoft.EntityFrameworkCore.Scaffolding.Internal.CompiledModelScaffolder.ScaffoldModel(IModel model, String outputDir, CompiledModelCodeGenerationOptions options)
at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.ScaffoldCompiledModel(String outputDir, String modelNamespace, DbContext context, String suffix, Boolean nativeAot, IServiceProvider services, ISet1 generatedFileNames) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.Optimize(String outputDir, String modelNamespace, String suffix, Boolean scaffoldModel, Boolean precompileQueries, DbContext context, Boolean optimizeAllInAssembly, Boolean nativeAot, List1 generatedFiles, HashSet1 generatedFileNames) at Microsoft.EntityFrameworkCore.Design.Internal.DbContextOperations.Optimize(String outputDir, String modelNamespace, String contextTypeName, String suffix, Boolean scaffoldModel, Boolean precompileQueries, Boolean nativeAot) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OptimizeContextImpl(String outputDir, String modelNamespace, String contextType, String suffix, Boolean scaffoldModel, Boolean precompileQueries, Boolean nativeAot) at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OptimizeContext.<>c__DisplayClass0_0.<.ctor>b__0() at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.<>c__DisplayClass3_01.b__0()
at Microsoft.EntityFrameworkCore.Design.OperationExecutor.OperationBase.Execute(Action action)
我不确定这是需求不被支持、配置错误还是Native AOT的实验性Bug导致的。虽然可以不用Native AOT生成模型,但据我了解未来没有它就无法生成预编译查询,所以必须解决这个问题。同时我也不清楚当前工具能否基于其他项目生成的模型来预编译查询并生成拦截器。
内容的提问来源于stack exchange,提问作者IanRawley

