如何解决Npgsql EF Provider 动态脚手架中未定义 NpgsqlValueGenerationStrategy
Postgres 13 数据库包含带有串行列的表:
CREATE TABLE algsa
(
id serial primary key;
)
使用 Npgsql 数据提供程序在 ASP.NET MVC Core 应用程序中使用下面的代码在运行时搭建脚手架导致异常
Message = CS0103:当前上下文中不存在名称“NpgsqlValueGenerationStrategy”
生成的代码包含
entity.Property(e => e.Id)
.HasColumnName("id")
.HasAnnotation("Npgsql:ValueGenerationStrategy",NpgsqlValueGenerationStrategy.SerialColumn);
如何修复 Npgsql 核心提供程序以支持它?添加 using 到生成的代码,如注释求解器问题所示,但应生成当前代码。 如果脚手架形式命令提示符,则此注解未创建且代码正确。
重现代码:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Scaffolding;
using Microsoft.EntityFrameworkCore.Scaffolding.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;
using Npgsql.EntityFrameworkCore.PostgreSQL.Diagnostics.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Scaffolding.Internal;
using Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;
//https://github.com/jdtcn/RuntimeEfCore
string connectionString = "Host=localhost;Database=dbwithserial";
var scaffolder = CreatePostgreScaffolder();
var dbOpts = new DatabaseModelFactoryOptions(schemas: new string[] { "public","firma1" });
var modelOpts = new ModelReverseEngineerOptions();
var codeGenOpts = new ModelCodeGenerationOptions()
{
RootNamespace = "Eeva.Data",ContextName = "EevaContext",ContextNamespace = "Eeva.Data",ModelNamespace = "Eeva.Data",SuppressConnectionStringWarning = true,SuppressOnConfiguring = true
};
var scaffoldedModelSources = scaffolder.ScaffoldModel(connectionString,dbOpts,modelOpts,codeGenOpts);
var sourceFiles = new List<string> {
// "using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;" + Environment.NewLine +
scaffoldedModelSources.ContextFile.Code
};
sourceFiles.AddRange(scaffoldedModelSources.AdditionalFiles.Select(f =>
f.Code)); ;
using var peStream = new MemoryStream();
bool enableLazyLoading = false;
var result = GenerateCode(sourceFiles,enableLazyLoading).Emit(peStream);
if (!result.Success)
{
var failures = result.Diagnostics
.Where(diagnostic => diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
var error = failures.FirstOrDefault();
// Message = CS0103: The name 'NpgsqlValueGenerationStrategy' does not exist in the current context
throw new Exception($"{error?.Id}: {error?.GetMessage()}");
}
var assemblyLoadContext = new AssemblyLoadContext("DbContext",isCollectible: !enableLazyLoading);
peStream.Seek(0,SeekOrigin.Begin);
var assembly = assemblyLoadContext.LoadFromStream(peStream);
var type = assembly.GetType("Eeva.Data.EevaContext"); // "TypedDataContext.Context.DataContext");
_ = type ?? throw new Exception("DataContext type not found");
var constr = type.GetConstructor(Type.EmptyTypes);
_ = constr ?? throw new Exception("DataContext ctor not found");
DbContext dynamicContext = (DbContext)constr.Invoke(null);
var entityTypes = dynamicContext.Model.GetEntityTypes();
Console.WriteLine($"Context contains {entityTypes.Count()} types");
foreach (var entityType in dynamicContext.Model.GetEntityTypes())
{
var items = (IQueryable<object>)dynamicContext.Query(entityType.Name);
Console.WriteLine($"Entity type: {entityType.ClrType.Name} contains {items.Count()} items");
}
static IReverseEngineerScaffolder CreatePostgreScaffolder()
{
return new ServiceCollection()
.AddEntityFrameworkNpgsql()
.AddLogging()
.AddEntityFrameworkDesignTimeServices()
.AddSingleton<LoggingDefinitions,NpgsqlLoggingDefinitions>()
.AddSingleton<IRelationalTypeMappingSource,NpgsqlTypeMappingSource>()
.AddSingleton<IAnnotationCodeGenerator,AnnotationCodeGenerator>()
.AddSingleton<IDatabaseModelFactory,NpgsqlDatabaseModelFactory>()
.AddSingleton<IProviderConfigurationCodeGenerator,NpgsqlCodeGenerator>()
.AddSingleton<IScaffoldingModelFactory,RelationalScaffoldingModelFactory>()
.BuildServiceProvider()
.GetRequiredService<IReverseEngineerScaffolder>();
}
static List<MetadataReference> CompilationReferences(bool enableLazyLoading)
{
var refs = new List<MetadataReference>();
var referencedAssemblies = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
refs.AddRange(referencedAssemblies.Select(a => MetadataReference.CreateFromFile(Assembly.Load(a).Location)));
refs.Add(MetadataReference.CreateFromFile(typeof(object).Assembly.Location));
refs.Add(MetadataReference.CreateFromFile(Assembly.Load("netstandard,Version=2.0.0.0").Location));
refs.Add(MetadataReference.CreateFromFile(typeof(System.Data.Common.DbConnection).Assembly.Location));
refs.Add(MetadataReference.CreateFromFile(typeof(System.Linq.Expressions.Expression).Assembly.Location));
if (enableLazyLoading)
{
refs.Add(MetadataReference.CreateFromFile(typeof(ProxiesExtensions).Assembly.Location));
}
return refs;
}
static CSharpCompilation GenerateCode(List<string> sourceFiles,bool enableLazyLoading)
{
var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp9); var parsedSyntaxTrees = sourceFiles.Select(f => SyntaxFactory.ParseSyntaxTree(f,options));
return CSharpCompilation.Create($"DataContext.dll",parsedSyntaxTrees,references: CompilationReferences(enableLazyLoading),options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary,optimizationLevel: OptimizationLevel.Release,assemblyIdentityComparer: DesktopAssemblyIdentityComparer.Default));
}
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。