Skip to content

Commit

Permalink
Introduce liftable constants to shaper to prepare for precompilation
Browse files Browse the repository at this point in the history
Part of #25009

json reader writer proper fix
  • Loading branch information
roji authored and maumar committed Mar 19, 2024
1 parent 7a41bd2 commit 05cf1e9
Show file tree
Hide file tree
Showing 133 changed files with 3,595 additions and 1,380 deletions.
1 change: 1 addition & 0 deletions EFCore.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,7 @@ The .NET Foundation licenses this file to you under the MIT license.
<s:Boolean x:Key="/Default/UserDictionary/Words/=Includable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=initializers/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=keyless/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=liftable/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lite_0027s/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=materializer/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=materializers/@EntryIndexedValue">True</s:Boolean>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.InMemory.Internal;
using Microsoft.EntityFrameworkCore.Internal;
using ExpressionExtensions = Microsoft.EntityFrameworkCore.Infrastructure.ExpressionExtensions;

namespace Microsoft.EntityFrameworkCore.InMemory.Query.Internal;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ public static readonly IDictionary<Type, ServiceCharacteristics> RelationalServi
{ typeof(IQuerySqlGeneratorFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IModificationCommandFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(ISqlAliasManagerFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IRelationalLiftableConstantFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(ICommandBatchPreparer), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IModificationCommandBatchFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) },
{ typeof(IRelationalSqlTranslatingExpressionVisitorFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) },
Expand Down Expand Up @@ -189,6 +190,9 @@ public override EntityFrameworkServicesBuilder TryAddCoreServices()
TryAdd<IQueryCompilationContextFactory, RelationalQueryCompilationContextFactory>();
TryAdd<IAdHocMapper, RelationalAdHocMapper>();
TryAdd<ISqlAliasManagerFactory, SqlAliasManagerFactory>();
TryAdd<ILiftableConstantFactory>(p => p.GetRequiredService<IRelationalLiftableConstantFactory>());
TryAdd<IRelationalLiftableConstantFactory, RelationalLiftableConstantFactory>();
TryAdd<ILiftableConstantProcessor, RelationalLiftableConstantProcessor>();

ServiceCollectionMap.GetInfrastructure()
.AddDependencySingleton<RelationalSqlGenerationHelperDependencies>()
Expand Down
18 changes: 18 additions & 0 deletions src/EFCore.Relational/Query/IRelationalLiftableConstantFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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.Query;

/// <summary>
/// TODO
/// </summary>
public interface IRelationalLiftableConstantFactory : ILiftableConstantFactory
{
/// <summary>
/// TODO
/// </summary>
LiftableConstantExpression CreateLiftableConstant(
Expression<Func<RelationalMaterializerLiftableConstantContext, object>> resolverExpression,
string variableName,
Type type);
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public class GroupBySingleQueryingEnumerable<TKey, TElement>
private readonly IReadOnlyList<ReaderColumn?>? _readerColumns;
private readonly Func<QueryContext, DbDataReader, TKey> _keySelector;
private readonly Func<QueryContext, DbDataReader, object[]> _keyIdentifier;
private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
//private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
private readonly IReadOnlyList<Func<object, object, bool>> _keyIdentifierValueComparers;
private readonly Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, TElement> _elementSelector;
private readonly Type _contextType;
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _queryLogger;
Expand All @@ -40,7 +41,8 @@ public GroupBySingleQueryingEnumerable(
IReadOnlyList<ReaderColumn?>? readerColumns,
Func<QueryContext, DbDataReader, TKey> keySelector,
Func<QueryContext, DbDataReader, object[]> keyIdentifier,
IReadOnlyList<ValueComparer> keyIdentifierValueComparers,
//IReadOnlyList<ValueComparer> keyIdentifierValueComparers,
IReadOnlyList<Func<object, object, bool>> keyIdentifierValueComparers,
Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, TElement> elementSelector,
Type contextType,
bool standAloneStateManager,
Expand Down Expand Up @@ -139,12 +141,12 @@ IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
}

private static bool CompareIdentifiers(IReadOnlyList<ValueComparer> valueComparers, object[] left, object[] right)
private static bool CompareIdentifiers(IReadOnlyList<Func<object, object, bool>> valueComparers, object[] left, object[] right)
{
// Ignoring size check on all for perf as they should be same unless bug in code.
for (var i = 0; i < left.Length; i++)
{
if (!valueComparers[i].Equals(left[i], right[i]))
if (!valueComparers[i](left[i], right[i]))
{
return false;
}
Expand All @@ -160,7 +162,8 @@ private sealed class Enumerator : IEnumerator<IGrouping<TKey, TElement>>
private readonly IReadOnlyList<ReaderColumn?>? _readerColumns;
private readonly Func<QueryContext, DbDataReader, TKey> _keySelector;
private readonly Func<QueryContext, DbDataReader, object[]> _keyIdentifier;
private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
//private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
private readonly IReadOnlyList<Func<object, object, bool>> _keyIdentifierValueComparers;
private readonly Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, TElement> _elementSelector;
private readonly Type _contextType;
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _queryLogger;
Expand Down Expand Up @@ -344,7 +347,8 @@ private sealed class AsyncEnumerator : IAsyncEnumerator<IGrouping<TKey, TElement
private readonly IReadOnlyList<ReaderColumn?>? _readerColumns;
private readonly Func<QueryContext, DbDataReader, TKey> _keySelector;
private readonly Func<QueryContext, DbDataReader, object[]> _keyIdentifier;
private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
//private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
private readonly IReadOnlyList<Func<object, object, bool>> _keyIdentifierValueComparers;
private readonly Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, TElement> _elementSelector;
private readonly Type _contextType;
private readonly IDiagnosticsLogger<DbLoggerCategory.Query> _queryLogger;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ public class GroupBySplitQueryingEnumerable<TKey, TElement>
private readonly IReadOnlyList<ReaderColumn?>? _readerColumns;
private readonly Func<QueryContext, DbDataReader, TKey> _keySelector;
private readonly Func<QueryContext, DbDataReader, object[]> _keyIdentifier;
private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
//private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
private readonly IReadOnlyList<Func<object, object, bool>> _keyIdentifierValueComparers;
private readonly Func<QueryContext, DbDataReader, ResultContext, SplitQueryResultCoordinator, TElement> _elementSelector;
private readonly Action<QueryContext, IExecutionStrategy, SplitQueryResultCoordinator>? _relatedDataLoaders;
private readonly Func<QueryContext, IExecutionStrategy, SplitQueryResultCoordinator, Task>? _relatedDataLoadersAsync;
Expand All @@ -42,7 +43,8 @@ public GroupBySplitQueryingEnumerable(
IReadOnlyList<ReaderColumn?>? readerColumns,
Func<QueryContext, DbDataReader, TKey> keySelector,
Func<QueryContext, DbDataReader, object[]> keyIdentifier,
IReadOnlyList<ValueComparer> keyIdentifierValueComparers,
//IReadOnlyList<ValueComparer> keyIdentifierValueComparers,
IReadOnlyList<Func<object, object, bool>> keyIdentifierValueComparers,
Func<QueryContext, DbDataReader, ResultContext, SplitQueryResultCoordinator, TElement> elementSelector,
Action<QueryContext, IExecutionStrategy, SplitQueryResultCoordinator>? relatedDataLoaders,
Func<QueryContext, IExecutionStrategy, SplitQueryResultCoordinator, Task>? relatedDataLoadersAsync,
Expand Down Expand Up @@ -145,12 +147,12 @@ IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
}

private static bool CompareIdentifiers(IReadOnlyList<ValueComparer> valueComparers, object[] left, object[] right)
private static bool CompareIdentifiers(IReadOnlyList<Func<object, object, bool>> valueComparers, object[] left, object[] right)
{
// Ignoring size check on all for perf as they should be same unless bug in code.
for (var i = 0; i < left.Length; i++)
{
if (!valueComparers[i].Equals(left[i], right[i]))
if (!valueComparers[i](left[i], right[i]))
{
return false;
}
Expand All @@ -166,7 +168,8 @@ private sealed class Enumerator : IEnumerator<IGrouping<TKey, TElement>>
private readonly IReadOnlyList<ReaderColumn?>? _readerColumns;
private readonly Func<QueryContext, DbDataReader, TKey> _keySelector;
private readonly Func<QueryContext, DbDataReader, object[]> _keyIdentifier;
private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
//private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
private readonly IReadOnlyList<Func<object, object, bool>> _keyIdentifierValueComparers;
private readonly Func<QueryContext, DbDataReader, ResultContext, SplitQueryResultCoordinator, TElement> _elementSelector;
private readonly Action<QueryContext, IExecutionStrategy, SplitQueryResultCoordinator>? _relatedDataLoaders;
private readonly Type _contextType;
Expand Down Expand Up @@ -340,7 +343,8 @@ private sealed class AsyncEnumerator : IAsyncEnumerator<IGrouping<TKey, TElement
private readonly IReadOnlyList<ReaderColumn?>? _readerColumns;
private readonly Func<QueryContext, DbDataReader, TKey> _keySelector;
private readonly Func<QueryContext, DbDataReader, object[]> _keyIdentifier;
private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
//private readonly IReadOnlyList<ValueComparer> _keyIdentifierValueComparers;
private readonly IReadOnlyList<Func<object, object, bool>> _keyIdentifierValueComparers;
private readonly Func<QueryContext, DbDataReader, ResultContext, SplitQueryResultCoordinator, TElement> _elementSelector;
private readonly Func<QueryContext, IExecutionStrategy, SplitQueryResultCoordinator, Task>? _relatedDataLoaders;
private readonly Type _contextType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,13 @@ private ProjectionBindingExpression AddClientProjection(Expression expression, T
return new ProjectionBindingExpression(_selectExpression, existingIndex, type);
}

private static T GetParameterValue<T>(QueryContext queryContext, string parameterName)
/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static T GetParameterValue<T>(QueryContext queryContext, string parameterName)
#pragma warning restore IDE0052 // Remove unread private members
=> (T)queryContext.ParameterValues[parameterName]!;

Expand Down
31 changes: 31 additions & 0 deletions src/EFCore.Relational/Query/Internal/SingleQueryingEnumerable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,37 @@

namespace Microsoft.EntityFrameworkCore.Query.Internal;

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
/// any release. You should only use it directly in your code with extreme caution and knowing that
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public static class SingleQueryingEnumerable
{
/// <summary>
/// TODO
/// </summary>
public static SingleQueryingEnumerable<T> Create<T>(
RelationalQueryContext relationalQueryContext,
RelationalCommandCache relationalCommandCache,
IReadOnlyList<ReaderColumn?>? readerColumns,
Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, T> shaper,
Type contextType,
bool standAloneStateManager,
bool detailedErrorsEnabled,
bool threadSafetyChecksEnabled)
=> new(
relationalQueryContext,
relationalCommandCache,
readerColumns,
shaper,
contextType,
standAloneStateManager,
detailedErrorsEnabled,
threadSafetyChecksEnabled);
}

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
/// the same compatibility standards as public APIs. It may be changed or removed without notice in
Expand Down
19 changes: 19 additions & 0 deletions src/EFCore.Relational/Query/RelationalLiftableConstantFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// 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.Query;

/// <summary>
/// TODO
/// </summary>
public class RelationalLiftableConstantFactory : LiftableConstantFactory, IRelationalLiftableConstantFactory
{
/// <summary>
/// TODO
/// </summary>
public virtual LiftableConstantExpression CreateLiftableConstant(
Expression<Func<RelationalMaterializerLiftableConstantContext, object>> resolverExpression,
string variableName,
Type type)
=> new(resolverExpression, variableName, type);
}
39 changes: 39 additions & 0 deletions src/EFCore.Relational/Query/RelationalLiftableConstantProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.EntityFrameworkCore.Query.Internal;

namespace Microsoft.EntityFrameworkCore.Query;

#pragma warning disable EF1001 // LiftableConstantProcessor is internal

/// <summary>
/// TODO
/// </summary>
public class RelationalLiftableConstantProcessor : LiftableConstantProcessor
{
private readonly RelationalMaterializerLiftableConstantContext _relationalMaterializerLiftableConstantContext;

/// <summary>
/// TODO
/// </summary>
public RelationalLiftableConstantProcessor(
ShapedQueryCompilingExpressionVisitorDependencies dependencies,
RelationalShapedQueryCompilingExpressionVisitorDependencies relationalDependencies)
: base(dependencies)
=> _relationalMaterializerLiftableConstantContext = new(dependencies, relationalDependencies);

/// <inheritdoc/>
protected override ConstantExpression InlineConstant(LiftableConstantExpression liftableConstant)
{
if (liftableConstant.ResolverExpression is Expression<Func<RelationalMaterializerLiftableConstantContext, object>>
resolverExpression)
{
var resolver = resolverExpression.Compile(preferInterpretation: true);
var value = resolver(_relationalMaterializerLiftableConstantContext);
return Expression.Constant(value, liftableConstant.Type);
}

return base.InlineConstant(liftableConstant);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// 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.Query;

/// <summary>
/// TODO
/// </summary>
public record RelationalMaterializerLiftableConstantContext(
ShapedQueryCompilingExpressionVisitorDependencies Dependencies,
RelationalShapedQueryCompilingExpressionVisitorDependencies RelationalDependencies)
: MaterializerLiftableConstantContext(Dependencies);
Loading

0 comments on commit 05cf1e9

Please # to comment.