рд░реЛрд╕рд▓рд┐рди рдФрд░ EF рдХреЛрд░: рд░рдирдЯрд╛рдЗрдо рдореЗрдВ DbContext рдХрд╛ рдирд┐рд░реНрдорд╛рдг

рдПрдВрдЯрд┐рдЯреА рдлреНрд░реЗрдорд╡рд░реНрдХ рдХреЛрд░ рдПрдХ рдХрдВрд╕реЛрд▓ рдХрдорд╛рдВрдб рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдореМрдЬреВрджрд╛ рдбреЗрдЯрд╛рдмреЗрд╕ рдХреЗ рд▓рд┐рдП рдореЙрдбрд▓ рдХреЛрдб рдФрд░ рдбреАрдмреЛрдирдЯреЗрдХреНрд╕реНрдЯ рдЙрддреНрдкрдиреНрди рдХрд░ рд╕рдХрддрд╛ рд╣реИ dotnet ef dbcontext scaffoldред рд╣рдо рд░рдирдЯрд╛рдЗрдо рдореЗрдВ DbContext рдЬрдирд░реЗрдЯ рдХрд░рдиреЗ рдХреА рдХреЛрд╢рд┐рд╢ рдХреНрдпреЛрдВ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ?


рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЕрдкрдиреЗ рдЖрд╡реЗрджрди рдореЗрдВ рд░рдирдЯрд╛рдЗрдо рдореЗрдВ рдХреИрд╕реЗ рдмрддрд╛рдКрдВрдЧрд╛:


  1. EF Core рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ DbContext рдХреЛрдб рдЬрдирд░реЗрдЯ рдХрд░реЗрдВред
  2. рдЗрд╕реЗ рд░реЛрд╕рд▓рд┐рди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдореЗрдореЛрд░реА рдореЗрдВ рд╕рдВрдХрд▓рд┐рдд рдХрд░реЗрдВред
  3. рдкрд░рд┐рдгрд╛рдореА рд╡рд┐рдзрд╛рдирд╕рднрд╛ рдбрд╛рдЙрдирд▓реЛрдб рдХрд░реЗрдВред
  4. рдЙрддреНрдкрдиреНрди DbContext рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рдмрдирд╛рдПрдБред
  5. рдкреНрд░рд╛рдкреНрдд 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 . , .


PostgreSQL
private 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>();

sqlite
private 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",

    //        ,
    //       runtime
    SuppressConnectionStringWarning = true
};

,


ScaffoldedModel scaffoldedModelSources =    
    scaffolder.ScaffoldModel(onnectionString, dbOpts, modelOpts, codeGenOpts);

:


//  
class ScaffoldedModel
{
    //   DbContext
    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))

    //     LazyLoading,     :
    // refs.Add(MetadataReference.CreateFromFile(
    //     typeof(ProxiesExtensions).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,





c#




, 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 рдХреЛрд░ рдореЗрдВ рдЕрд╕реЗрдВрдмрд▓реА рдЕрдирд▓реЛрдбрд┐рдмрд┐рд▓рд┐рдЯреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдФрд░ рдбрд┐рдмрдЧ рдХреИрд╕реЗ рдХрд░реЗрдВ


рдЕрдкрдирд╛ рд╕рдордп рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж!


рдореЗрд░реЗ рдкрд╛рд╕ рдХреБрдЫ рдФрд░ рд╡рд┐рд╖рдп рд╣реИрдВ рдЬрд┐рдирдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдореИрдВ рд▓рд┐рдЦрдирд╛ рдЪрд╛рд╣реВрдВрдЧрд╛ред рдпрджрд┐ рдЖрдк рд╕рд░реНрд╡реЗрдХреНрд╖рдг рдХреЗ рд╡рд┐рд╖рдпреЛрдВ рдореЗрдВ рд╕рдВрдХреЗрдд рджреЗрддреЗ рд╣реИрдВ, рдЬреЛ рдЖрдкрдХреЗ рд╣рд┐рдд рдореЗрдВ рд╣реЛрдВрдЧреЗ, рддреЛ рдореИрдВ рдЖрднрд╛рд░реА рд░рд╣реВрдВрдЧрд╛ред


All Articles