рдПрдВрдЯрд┐рдЯреА рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЛрд░ рдПрдХ рдХрдВрд╕реЛрд▓ рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдореМрдЬреВрджрд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд▓рд┐рдП рдореЙрдбрд▓ рдХреЛрдб рдФрд░ рдбреАрдмреЛрдирдЯреЗрдХреНрд╕реНрдЯ рдЙрддреНрдкрдиреНрди рдХрд░ рд╕рдХрддрд╛ рд╣реИ dotnet ef dbcontext scaffold
ред рд╣рдо рд░рдирдЯрд╛рдЗрдо рдореЗрдВ DbContext рдЬрдирд░реЗрдЯ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ?
рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЕрдкрдиреЗ рдЖрд╡реЗрджрди рдореЗрдВ рд░рдирдЯрд╛рдЗрдо рдореЗрдВ рдХреИрд╕реЗ рдмрддрд╛рдКрдВрдЧрд╛:
- EF Core рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ DbContext рдХреЛрдб рдЬрдирд░реЗрдЯ рдХрд░реЗрдВред
- рдЗрд╕реЗ рд░реЛрд╕рд▓рд┐рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдореЗрдореЛрд░реА рдореЗрдВ рд╕рдВрдХрд▓рд┐рдд рдХрд░реЗрдВред
- рдкрд░рд┐рдгрд╛рдореА рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВред
- рдЙрддреНрдкрдиреНрди DbContext рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдПрдБред
- рдкреНрд░рд╛рдкреНрдд DbContext рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд╕рд╛рде рдХрд╛рдо рдХрд░реЗрдВред
рдПрдХ рдЙрджрд╛рд╣рд░рдг рдЬреАрдердм рдкрд░ рдЙрдкрд▓рдмреНрдз рд╣реИред
рдХрд╛рдо рдХреА рддреИрдпрд╛рд░реА
рдЖрд╡реЗрджрди рдХреЗ рд▓рд┐рдП рдордВрдЪ NET Core 3.1.3 рд╣реЛрдЧрд╛ред
рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдореИрдВ рдПрдордПрд╕ SQL тАЛтАЛрдбреЗрдЯрд╛рдмреЗрд╕ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░реВрдВрдЧрд╛, рд╣рдореЗрдВ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдиреЗрдХреНрд╢рди рд╕реНрдЯреНрд░рд┐рдВрдЧ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╣рд╛рд▓рд╛рдБрдХрд┐, рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╣реА рдИрдПрдл рдХреЛрд░ рджреНрд╡рд╛рд░рд╛ рд╕рдорд░реНрдерд┐рдд рдХрд┐рд╕реА рднреА рдбреЗрдЯрд╛рдмреЗрд╕ рдЗрдВрдЬрди рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ (рдореИрдВрдиреЗ рд╕рд╛рдЗрдХреНрд▓рд╛рдЗрдЯ рдФрд░ рдкреЛрд╕реНрдЯрдЧреНрд░реЗрдЬ рдХрд╛ рдкрд░реАрдХреНрд╖рдг рдХрд┐рдпрд╛)ред
рдЪрд▓реЛ рдПрдХ рдХрдВрд╕реЛрд▓ рдПрдкреНрд▓рд┐рдХреЗрд╢рди рдмрдирд╛рдПрдВ, рдЗрд╕рдореЗрдВ рдЖрд╡рд╢реНрдпрдХ рдкреИрдХреЗрдЬ рдЬреЛрдбрд╝реЗрдВ:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis" Version="3.5.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Proxies" Version="3.1.3" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.3" />
<PackageReference Include="Bricelam.EntityFrameworkCore.Pluralizer" Version="1.0.0" />
</ItemGroup>
</Project>
рдХреЛрдб рдЬрдирд░реЗрдЯрд░ рдкреИрдХреЗрдЬ рдореЗрдВ рд╣реИ Microsoft.EntityFrameworkCore.Design
ред рдпрджрд┐ рдЖрдк рдкреИрдХреЗрдЬ рдореИрдиреЗрдЬрд░ рдХрдВрд╕реЛрд▓ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЗрд╕ рдкреИрдХреЗрдЬ рдХреЛ рд╕реНрдерд╛рдкрд┐рдд рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдирд┐рдореНрди рдХреЛрдб рдЖрдкрдХреЗ * .csproj рдореЗрдВ рдЬреЛрдбрд╝рд╛ рдЬрд╛рдПрдЧрд╛:
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
рдпрд╣ рдХреЛрдб рдХрд╣рддрд╛ рд╣реИ [ 1 ] рдХрд┐ рдкреИрдХреЗрдЬ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдХреЗрд╡рд▓ рд╡рд┐рдХрд╛рд╕ рдХреЗ рджреМрд░рд╛рди рд╣реЛрддреА рд╣реИ, рдФрд░ рд░рдирдЯрд╛рдЗрдо рдореЗрдВ рдЗрд╕рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рд╣рдореЗрдВ рд░рдирдЯрд╛рдЗрдо рдореЗрдВ рдЗрд╕рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрдЧреА, рдЗрд╕рд▓рд┐рдП рд╣рдореЗрдВ рдкреИрдХреЗрдЬ рдХреЛ рдЗрд╕ рддрд░рд╣ рдЖрдпрд╛рдд рдХрд░рдирд╛ рд╣реЛрдЧрд╛:
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.3" />
1. рдХреЛрдб рдЬрдирд░реЗрдЯ рдХрд░реЗрдВ
рдЗрдХрд╛рдИ рдврд╛рдВрдЪреЗ рдХреЛрд░ рдореЗрдВ, рдХреЛрдб рдПрдХ рд╕реЗрд╡рд╛ рдЙрддреНрдкрдиреНрди рдХрд░рддрд╛ рд╣реИ IReverseEngineerScaffolder
:
interface IReverseEngineerScaffolder
{
ScaffoldedModel ScaffoldModel(
string connectionString,
//
DatabaseModelFactoryOptions databaseOptions,
//
ModelReverseEngineerOptions modelOptions,
// ,
ModelCodeGenerationOptions codeOptions);
}
рдЗрд╕ рд╕реЗрд╡рд╛ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдиреЗ рдХрд╛ рд╕рдмрд╕реЗ рдЖрд╕рд╛рди рддрд░реАрдХрд╛ рдЗрд╕рдХреЗ рд▓рд┐рдП рдПрдХ рдбрд┐рдкреЗрдВрдбреЗрдВрд╕реА рдЗрдВрдЬреЗрдХреНрд╢рди рдХрдВрдЯреЗрдирд░ рдмрдирд╛рдирд╛ рд╣реИред
:
IReverseEngineerScaffolder CreateMssqlScaffolder() =>
new ServiceCollection()
.AddEntityFrameworkSqlServer()
.AddLogging()
.AddEntityFrameworkDesignTimeServices()
.AddSingleton<LoggingDefinitions, SqlServerLoggingDefinitions>()
.AddSingleton<IRelationalTypeMappingSource, SqlServerTypeMappingSource>()
.AddSingleton<IAnnotationCodeGenerator, AnnotationCodeGenerator>()
.AddSingleton<IDatabaseModelFactory, SqlServerDatabaseModelFactory>()
.AddSingleton<IProviderConfigurationCodeGenerator, SqlServerCodeGenerator>()
.AddSingleton<IScaffoldingModelFactory, RelationalScaffoldingModelFactory>()
.AddSingleton<IPluralizer, Bricelam.EntityFrameworkCore.Design.Pluralizer>()
.BuildServiceProvider()
.GetRequiredService<IReverseEngineerScaffolder>();
IPluralizer
. , .
PostgreSQLprivate IReverseEngineerScaffolder CreatePostgreScaffolder() =>
new ServiceCollection()
.AddEntityFrameworkNpgsql()
.AddLogging()
.AddEntityFrameworkDesignTimeServices()
.AddSingleton<LoggingDefinitions, NpgsqlLoggingDefinitions>()
.AddSingleton<IRelationalTypeMappingSource, NpgsqlTypeMappingSource>()
.AddSingleton<IAnnotationCodeGenerator, AnnotationCodeGenerator>()
.AddSingleton<IDatabaseModelFactory, NpgsqlDatabaseModelFactory>()
.AddSingleton<IProviderConfigurationCodeGenerator, NpgsqlCodeGenerator>()
.AddSingleton<IScaffoldingModelFactory, RelationalScaffoldingModelFactory>()
.AddSingleton<IPluralizer, Bricelam.EntityFrameworkCore.Design.Pluralizer>()
.BuildServiceProvider()
.GetRequiredService<IReverseEngineerScaffolder>();
sqliteprivate IReverseEngineerScaffolder CreateSqliteScaffolder() =>
new ServiceCollection()
.AddEntityFrameworkSqlite()
.AddLogging()
.AddEntityFrameworkDesignTimeServices()
.AddSingleton<LoggingDefinitions, SqliteLoggingDefinitions>()
.AddSingleton<IRelationalTypeMappingSource, SqliteTypeMappingSource>()
.AddSingleton<IAnnotationCodeGenerator, AnnotationCodeGenerator>()
.AddSingleton<IDatabaseModelFactory, SqliteDatabaseModelFactory>()
.AddSingleton<IProviderConfigurationCodeGenerator, SqliteCodeGenerator>()
.AddSingleton<IScaffoldingModelFactory, RelationalScaffoldingModelFactory>()
.AddSingleton<IPluralizer, Bricelam.EntityFrameworkCore.Design.Pluralizer>()
.BuildServiceProvider()
.GetRequiredService<IReverseEngineerScaffolder>();
:
var scaffolder = CreateMssqlScaffolder();
:
var dbOpts = new DatabaseModelFactoryOptions();
var modelOpts = new ModelReverseEngineerOptions();
var codeGenOpts = new ModelCodeGenerationOptions()
{
RootNamespace = "TypedDataContext",
ContextName = "DataContext",
ContextNamespace = "TypedDataContext.Context",
ModelNamespace = "TypedDataContext.Models",
SuppressConnectionStringWarning = true
};
,
ScaffoldedModel scaffoldedModelSources =
scaffolder.ScaffoldModel(onnectionString, dbOpts, modelOpts, codeGenOpts);
:
class ScaffoldedModel
{
public virtual ScaffoldedFile ContextFile { get; set; }
public virtual IList<ScaffoldedFile> AdditionalFiles { get; }
}
Lazy Loading, UseLazyLoadingProxies()
:
var contextFile = scaffoldedModelSources.ContextFile.Code
.Replace(".UseSqlServer", ".UseLazyLoadingProxies().UseSqlServer");
, , .
2. Roslyn
Roslyn, :
CSharpCompilation GenerateCode(List<string> sourceFiles)
{
var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp8);
var parsedSyntaxTrees = sourceFiles
.Select(f => SyntaxFactory.ParseSyntaxTree(f, options));
return CSharpCompilation.Create($"DataContext.dll",
parsedSyntaxTrees,
references: GetCompilationReferences(),
options: new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
optimizationLevel: OptimizationLevel.Release));
}
, :
List<MetadataReference> CompilationReferences()
{
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))
return refs;
}
:
MemoryStream peStream = new MemoryStream();
EmitResult emitResult = GenerateCode(sourceFiles).Emit(peStream);
, emitResult.Success
true
, peStream
.
- , . emitResult
.
3.
, , :
var assemblyLoadContext = new AssemblyLoadContext("DbContext", isCollectible);
var assembly = assemblyLoadContext.LoadFromStream(peStream);
isCollectible
. , . NET Core 3 [2].
, , . [5]:
assemblyLoadContext.Unload();
LazyLoading, EF Core Proxy- , DefaultLoadContext, collectible
. NonCollectible- collectible-, collectible
LazyLoading. [3][4], .
4. DbContext
, DbContext.
var type = assembly.GetType("TypedDataContext.Context.DataContext");
var constructor = type.GetConstructor(Type.EmptyTypes);
DbContext dynamicContext = (DbContext)constructor.Invoke(null);
, :
public static class DynamicContextExtensions
{
public static IQueryable Query(this DbContext context, string entityName) =>
context.Query(context.Model.FindEntityType(entityName).ClrType);
static readonly MethodInfo SetMethod =
typeof(DbContext).GetMethod(nameof(DbContext.Set), 1, Array.Empty<Type>()) ??
throw new Exception($"Type not found: DbContext.Set");
public static IQueryable Query(this DbContext context, Type entityType) =>
(IQueryable)SetMethod.MakeGenericMethod(entityType)?.Invoke(context, null) ??
throw new Exception($"Type not found: {entityType.FullName}");
}
Reflection Set<>
DbContext.
, :
foreach (var entityType in dynamicContext.Model.GetEntityTypes())
{
var items = (IQueryable<object>)dynamicContext.Query(entityType.Name);
Console.Write($"Entity type: {entityType.ClrType.Name} ");
Console.WriteLine($"contains {items.Count()} items");
}
, , , .
ASP.NET Core Blazor , , SQL, MS SQL, PostrgreSQL, sqlite,
, EF Core DbContext runtime. NET Core тАФ collectible assemblies
, , .
github.
[1] (PackageReference)
[2] Collectible assemblies in .NET Core 3.0
[3] Lazy loading proxy doesn't support entity inside collectible assembly #18272
[рек] рд╕рдкреЛрд░реНрдЯреЗрдмрд▓ рдбрд╛рдпрдиреЗрдорд┐рдХ рдЕрд╕реЗрдВрдмрд▓рд┐рдпреЛрдВ # рек ]рей
[рел] .NET рдХреЛрд░ рдореЗрдВ рдЕрд╕реЗрдВрдмрд▓реА рдЕрдирд▓реЛрдбрд┐рдмрд┐рд▓рд┐рдЯреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдФрд░ рдбрд┐рдмрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВ
рдЕрдкрдирд╛ рд╕рдордп рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!
рдореЗрд░реЗ рдкрд╛рд╕ рдХреБрдЫ рдФрд░ рд╡рд┐рд╖рдп рд╣реИрдВ рдЬрд┐рдирдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореИрдВ рд▓рд┐рдЦрдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ред рдпрджрд┐ рдЖрдк рд╕рд░реНрд╡реЗрдХреНрд╖рдг рдХреЗ рд╡рд┐рд╖рдпреЛрдВ рдореЗрдВ рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВ, рдЬреЛ рдЖрдкрдХреЗ рд╣рд┐рдд рдореЗрдВ рд╣реЛрдВрдЧреЗ, рддреЛ рдореИрдВ рдЖрднрд╛рд░реА рд░рд╣реВрдВрдЧрд╛ред