Skip to content

Commit

Permalink
Implement precompiled queries
Browse files Browse the repository at this point in the history
  • Loading branch information
roji committed Mar 12, 2024
1 parent cb459fc commit 3d6bf1f
Show file tree
Hide file tree
Showing 85 changed files with 8,362 additions and 345 deletions.
4 changes: 3 additions & 1 deletion EFCore.sln.DotSettings
Expand Up @@ -301,7 +301,6 @@ The .NET Foundation licenses this file to you under the MIT license.
<s:Boolean x:Key="/Default/UserDictionary/Words/=efcore/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=evaluatability/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=evaluatable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Evaluatables/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=evaluatables/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=fallbacks/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=funcletization/@EntryIndexedValue">True</s:Boolean>
Expand All @@ -325,7 +324,10 @@ The .NET Foundation licenses this file to you under the MIT license.&#xD;
<s:Boolean x:Key="/Default/UserDictionary/Words/=Poolable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Postgre/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=precompilation/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=precompiling/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=prunable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=precompilation/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pubternal/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=pushdown/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=queryables/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=remapper/@EntryIndexedValue">True</s:Boolean>
Expand Down
14 changes: 14 additions & 0 deletions src/EFCore.Analyzers/EFDiagnostics.cs
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace Microsoft.EntityFrameworkCore;

/// <summary>
/// Contains IDs of diagnostics created by EF analyzers and other mechanisms.
/// </summary>
public static class EFDiagnostics
{
public const string InternalUsage = "EF1001";
public const string SuppressUninitializedDbSetRule = "EFSPR1001";
public const string PrecompiledQueryExperimental = "EF2001";
}
3 changes: 1 addition & 2 deletions src/EFCore.Analyzers/InternalUsageDiagnosticAnalyzer.cs
Expand Up @@ -12,13 +12,12 @@ namespace Microsoft.EntityFrameworkCore;
[DiagnosticAnalyzer(LanguageNames.CSharp)]
public sealed class InternalUsageDiagnosticAnalyzer : DiagnosticAnalyzer
{
public const string Id = "EF1001";
private static readonly int EFLen = "EntityFrameworkCore".Length;

private static readonly DiagnosticDescriptor Descriptor
// HACK: Work around dotnet/roslyn-analyzers#5890 by not using target-typed new
= new DiagnosticDescriptor(
Id,
EFDiagnostics.InternalUsage,
title: AnalyzerStrings.InternalUsageTitle,
messageFormat: AnalyzerStrings.InternalUsageMessageFormat,
category: "Usage",
Expand Down
Expand Up @@ -12,7 +12,7 @@ namespace Microsoft.EntityFrameworkCore;
public sealed class UninitializedDbSetDiagnosticSuppressor : DiagnosticSuppressor
{
private static readonly SuppressionDescriptor SuppressUninitializedDbSetRule = new(
id: "EFSPR1001",
id: EFDiagnostics.SuppressUninitializedDbSetRule,
suppressedDiagnosticId: "CS8618",
justification: AnalyzerStrings.UninitializedDbSetWarningSuppressionJustification);

Expand Down
Expand Up @@ -19,8 +19,9 @@ public class CosmosQueryCompilationContext : QueryCompilationContext
/// </summary>
public CosmosQueryCompilationContext(
QueryCompilationContextDependencies dependencies,
bool async)
: base(dependencies, async)
bool async,
bool precompiling)
: base(dependencies, async, precompiling)
{
}

Expand Down
Expand Up @@ -3,6 +3,7 @@

using Microsoft.EntityFrameworkCore.Design.Internal;
using Microsoft.EntityFrameworkCore.Migrations.Internal;
using Microsoft.EntityFrameworkCore.Query.Internal;
using Microsoft.EntityFrameworkCore.Scaffolding.Internal;

namespace Microsoft.EntityFrameworkCore.Design;
Expand Down Expand Up @@ -60,6 +61,11 @@ public static class DesignTimeServiceCollectionExtensions
.TryAddSingleton<IScaffoldingTypeMapper, ScaffoldingTypeMapper>()
.TryAddSingleton<MigrationsCodeGeneratorDependencies, MigrationsCodeGeneratorDependencies>()
.TryAddSingleton<ModelCodeGeneratorDependencies, ModelCodeGeneratorDependencies>()
// Query precompilation
.TryAddSingleton<IPrecompiledQueryCodeGenerator, PrecompiledQueryCodeGenerator>()
.TryAddSingleton<IQueryLocator, QueryLocator>()
.TryAddScoped<IReverseEngineerScaffolder, ReverseEngineerScaffolder>()
.TryAddScoped<MigrationsScaffolderDependencies, MigrationsScaffolderDependencies>()
.TryAddScoped<IMigrationsScaffolder, MigrationsScaffolder>()
Expand Down
25 changes: 21 additions & 4 deletions src/EFCore.Design/Design/Internal/CSharpHelper.cs
Expand Up @@ -1556,6 +1556,7 @@ private string ToSourceCode(SyntaxNode node)
public virtual string Statement(
Expression node,
ISet<string> collectedNamespaces,
ISet<string> unsafeAccessors,
IReadOnlyDictionary<object, string>? constantReplacements,
IReadOnlyDictionary<MemberAccess, string>? memberAccessReplacements)
{
Expand All @@ -1581,11 +1582,18 @@ private string ToSourceCode(SyntaxNode node)
}
}

return ToSourceCode(_translator.TranslateStatement(
var unsafeAccessorDeclarations = new HashSet<MethodDeclarationSyntax>();
var code = ToSourceCode(_translator.TranslateStatement(
node,
constantReplacementExpressions,
memberAccessReplacementExpressions,
collectedNamespaces));
collectedNamespaces,
unsafeAccessorDeclarations));

// TODO: Possibly improve this (e.g. expose a single string that contains all the accessors concatenated?)
unsafeAccessors.UnionWith(unsafeAccessorDeclarations.Select(ToSourceCode));

return code;
}

/// <summary>
Expand All @@ -1597,6 +1605,7 @@ private string ToSourceCode(SyntaxNode node)
public virtual string Expression(
Expression node,
ISet<string> collectedNamespaces,
ISet<string> unsafeAccessors,
IReadOnlyDictionary<object, string>? constantReplacements,
IReadOnlyDictionary<MemberAccess, string>? memberAccessReplacements)
{
Expand All @@ -1622,11 +1631,19 @@ private string ToSourceCode(SyntaxNode node)
}
}

return ToSourceCode(_translator.TranslateExpression(
var unsafeAccessorDeclarations = new HashSet<MethodDeclarationSyntax>();

var code = ToSourceCode(_translator.TranslateExpression(
node,
constantReplacementExpressions,
memberAccessReplacementExpressions,
collectedNamespaces));
collectedNamespaces,
unsafeAccessorDeclarations));

// TODO: Possibly improve this (e.g. expose a single string that contains all the accessors concatenated?)
unsafeAccessors.UnionWith(unsafeAccessorDeclarations.Select(ToSourceCode));

return code;
}

private static bool IsIdentifierStartCharacter(char ch)
Expand Down
4 changes: 3 additions & 1 deletion src/EFCore.Design/EFCore.Design.csproj
Expand Up @@ -8,7 +8,7 @@
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DevelopmentDependency>true</DevelopmentDependency>
<ImplicitUsings>true</ImplicitUsings>
<NoWarn>EF1003</NoWarn> <!-- Precompiled query is experimental -->
<NoWarn>EF2001</NoWarn> <!-- Precompiled query is experimental -->
</PropertyGroup>

<ItemGroup>
Expand Down Expand Up @@ -58,6 +58,8 @@
<ItemGroup>
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Workspaces" Version="$(MicrosoftCodeAnalysisVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.MSBuild" Version="$(MicrosoftCodeAnalysisVersion)" />
<PackageReference Include="Microsoft.Build.Locator" Version="1.5.5" />
<PackageReference Include="Microsoft.Extensions.DependencyModel" Version="$(MicrosoftExtensionsDependencyModelVersion)" />
<PackageReference Include="Microsoft.Extensions.HostFactoryResolver.Sources" PrivateAssets="All" Version="$(MicrosoftExtensionsHostFactoryResolverSourcesVersion)" />
<PackageReference Include="Mono.TextTemplating" Version="3.0.0-preview-0052-g5d0f76c785" />
Expand Down
6 changes: 6 additions & 0 deletions src/EFCore.Design/Properties/DesignStrings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions src/EFCore.Design/Properties/DesignStrings.resx
Expand Up @@ -359,6 +359,9 @@ Change your target project to the migrations project by using the Package Manage
<data name="ProviderReturnedNullModel" xml:space="preserve">
<value>Metadata model returned should not be null. Provider: {providerTypeName}.</value>
</data>
<data name="QueryComprehensionSyntaxNotSupportedInPrecompiledQueries" xml:space="preserve">
<value>LINQ query comprehension syntax is currently unsupported in precompiled queries.</value>
</data>
<data name="ReadOnlyFiles" xml:space="preserve">
<value>No files were generated in directory '{outputDirectoryName}'. The following file(s) already exist(s) and must be made writeable to continue: {readOnlyFiles}.</value>
</data>
Expand Down

0 comments on commit 3d6bf1f

Please sign in to comment.