Skip to content

Commit

Permalink
Use the pre-convention type mapping configuration in query
Browse files Browse the repository at this point in the history
Part of #25084
  • Loading branch information
AndriySvyryd committed Aug 16, 2021
1 parent cc1d81a commit d4bb806
Show file tree
Hide file tree
Showing 76 changed files with 397 additions and 849 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,6 @@ public static IServiceCollection AddEntityFrameworkCosmos(this IServiceCollectio
.TryAdd<IDatabaseCreator, CosmosDatabaseCreator>()
.TryAdd<IQueryContextFactory, CosmosQueryContextFactory>()
.TryAdd<ITypeMappingSource, CosmosTypeMappingSource>()

// New Query pipeline
.TryAdd<IQueryableMethodTranslatingExpressionVisitorFactory, CosmosQueryableMethodTranslatingExpressionVisitorFactory>()
.TryAdd<IShapedQueryCompilingExpressionVisitorFactory, CosmosShapedQueryCompilingExpressionVisitorFactory>()
.TryAdd<ISingletonOptions, ICosmosSingletonOptions>(p => p.GetRequiredService<ICosmosSingletonOptions>())
Expand All @@ -128,10 +126,10 @@ public static IServiceCollection AddEntityFrameworkCosmos(this IServiceCollectio
b => b
.TryAddSingleton<ICosmosSingletonOptions, CosmosSingletonOptions>()
.TryAddSingleton<ISingletonCosmosClientWrapper, SingletonCosmosClientWrapper>()
.TryAddSingleton<ISqlExpressionFactory, SqlExpressionFactory>()
.TryAddSingleton<IQuerySqlGeneratorFactory, QuerySqlGeneratorFactory>()
.TryAddSingleton<IMethodCallTranslatorProvider, CosmosMethodCallTranslatorProvider>()
.TryAddSingleton<IMemberTranslatorProvider, CosmosMemberTranslatorProvider>()
.TryAddScoped<ISqlExpressionFactory, SqlExpressionFactory>()
.TryAddScoped<IMemberTranslatorProvider, CosmosMemberTranslatorProvider>()
.TryAddScoped<IMethodCallTranslatorProvider, CosmosMethodCallTranslatorProvider>()
.TryAddScoped<ICosmosClientWrapper, CosmosClientWrapper>()
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Utilities;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal
{
Expand All @@ -14,11 +13,6 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal
/// 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.
/// </para>
/// <para>
/// The service lifetime is <see cref="ServiceLifetime.Singleton" />. This means a single instance
/// is used by many <see cref="DbContext" /> instances. The implementation must be thread-safe.
/// This service cannot depend on services registered as <see cref="ServiceLifetime.Scoped" />.
/// </para>
/// </summary>
public class CosmosQueryTranslationPostprocessorFactory : IQueryTranslationPostprocessorFactory
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Utilities;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal
{
Expand All @@ -14,11 +13,6 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal
/// 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.
/// </para>
/// <para>
/// The service lifetime is <see cref="ServiceLifetime.Singleton" />. This means a single instance
/// is used by many <see cref="DbContext" /> instances. The implementation must be thread-safe.
/// This service cannot depend on services registered as <see cref="ServiceLifetime.Scoped" />.
/// </para>
/// </summary>
public class CosmosQueryTranslationPreprocessorFactory : IQueryTranslationPreprocessorFactory
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,6 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal
/// 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.
/// </para>
/// <para>
/// The service lifetime is <see cref="ServiceLifetime.Singleton" />. This means a single instance
/// is used by many <see cref="DbContext" /> instances. The implementation must be thread-safe.
/// This service cannot depend on services registered as <see cref="ServiceLifetime.Scoped" />.
/// </para>
/// </summary>
public class CosmosQueryableMethodTranslatingExpressionVisitorFactory : IQueryableMethodTranslatingExpressionVisitorFactory
{
Expand Down
8 changes: 0 additions & 8 deletions src/EFCore.Cosmos/Query/Internal/ISqlExpressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,6 @@ public interface ISqlExpressionFactory
/// </summary>
SqlExpression ApplyDefaultTypeMapping(SqlExpression? sqlExpression);

/// <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>
CoreTypeMapping FindMapping(Type type);

/// <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
25 changes: 8 additions & 17 deletions src/EFCore.Cosmos/Query/Internal/SqlExpressionFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Internal
public class SqlExpressionFactory : ISqlExpressionFactory
{
private readonly ITypeMappingSource _typeMappingSource;
private readonly IModel _model;
private readonly CoreTypeMapping _boolTypeMapping;

/// <summary>
Expand All @@ -33,9 +34,10 @@ public class SqlExpressionFactory : ISqlExpressionFactory
/// 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 SqlExpressionFactory(ITypeMappingSource typeMappingSource)
public SqlExpressionFactory(ITypeMappingSource typeMappingSource, IModel model)
{
_typeMappingSource = typeMappingSource;
_model = model;
_boolTypeMapping = typeMappingSource.FindMapping(typeof(bool));
}

Expand All @@ -46,12 +48,10 @@ public SqlExpressionFactory(ITypeMappingSource typeMappingSource)
/// doing so can result in application failures when updating to a new Entity Framework Core release.
/// </summary>
public virtual SqlExpression ApplyDefaultTypeMapping(SqlExpression sqlExpression)
{
return sqlExpression == null
=> sqlExpression == null
|| sqlExpression.TypeMapping != null
? sqlExpression
: ApplyTypeMapping(sqlExpression, _typeMappingSource.FindMapping(sqlExpression.Type));
}
: ApplyTypeMapping(sqlExpression, _model.FindMapping(sqlExpression.Type));

/// <summary>
/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to
Expand Down Expand Up @@ -170,8 +170,8 @@ private SqlExpression ApplyTypeMappingOnSqlBinary(
inferredTypeMapping = ExpressionExtensions.InferTypeMapping(left, right)
// We avoid object here since the result does not get typeMapping from outside.
?? (left.Type != typeof(object)
? _typeMappingSource.FindMapping(left.Type)
: _typeMappingSource.FindMapping(right.Type));
? _model.FindMapping(left.Type)
: _model.FindMapping(right.Type));
resultType = typeof(bool);
resultTypeMapping = _boolTypeMapping;
}
Expand Down Expand Up @@ -216,15 +216,6 @@ private SqlExpression ApplyTypeMappingOnSqlBinary(
resultTypeMapping);
}

/// <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 virtual CoreTypeMapping FindMapping(Type type)
=> _typeMappingSource.FindMapping(type);

/// <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 Expand Up @@ -495,7 +486,7 @@ public virtual SqlConditionalExpression Condition(SqlExpression test, SqlExpress
/// </summary>
public virtual InExpression In(SqlExpression item, SqlExpression values, bool negated)
{
var typeMapping = item.TypeMapping ?? _typeMappingSource.FindMapping(item.Type);
var typeMapping = item.TypeMapping ?? _model.FindMapping(item.Type);

item = ApplyTypeMapping(item, typeMapping);
values = ApplyTypeMapping(values, typeMapping);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ public static IServiceCollection AddEntityFrameworkDesignTimeServices(
.TryAddSingleton<INamedConnectionStringResolver>(
new DesignTimeConnectionStringResolver(applicationServiceProviderAccessor))
.TryAddSingleton<IPluralizer, HumanizerPluralizer>()
.TryAddSingleton<IReverseEngineerScaffolder, ReverseEngineerScaffolder>()
.TryAddSingleton<IScaffoldingModelFactory, RelationalScaffoldingModelFactory>()
.TryAddSingleton<IScaffoldingTypeMapper, ScaffoldingTypeMapper>()
.TryAddSingleton<MigrationsCodeGeneratorDependencies, MigrationsCodeGeneratorDependencies>()
.TryAddSingleton<ModelCodeGeneratorDependencies, ModelCodeGeneratorDependencies>()
.TryAddScoped<IReverseEngineerScaffolder, ReverseEngineerScaffolder>()
.TryAddScoped<MigrationsScaffolderDependencies, MigrationsScaffolderDependencies>()
.TryAddScoped<IMigrationsScaffolder, MigrationsScaffolder>()
.TryAddScoped<ISnapshotModelProcessor, SnapshotModelProcessor>());
Expand Down
3 changes: 2 additions & 1 deletion src/EFCore.Design/Design/Internal/DatabaseOperations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,9 @@ public virtual SavedModelFiles ScaffoldContext(
: outputDir;

var services = _servicesBuilder.Build(provider);
using var scope = services.CreateScope();

var scaffolder = services.GetRequiredService<IReverseEngineerScaffolder>();
var scaffolder = scope.ServiceProvider.GetRequiredService<IReverseEngineerScaffolder>();

var finalModelNamespace = modelNamespace ?? GetNamespaceFromOutputPath(outputDir);
var finalContextNamespace =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public virtual Expression Translate(InMemoryQueryExpression queryExpression, Exp

_projectionMembers.Push(new ProjectionMember());

var expandedExpression = _queryableMethodTranslatingExpressionVisitor.ExpandWeakEntities(_queryExpression, expression);
var expandedExpression = _queryableMethodTranslatingExpressionVisitor.ExpandSharedTypeEntities(_queryExpression, expression);
var result = Visit(expandedExpression);

if (result == QueryCompilationContext.NotTranslatedExpression)
Expand All @@ -73,7 +73,7 @@ public virtual Expression Translate(InMemoryQueryExpression queryExpression, Exp
_entityProjectionCache = new();
_clientProjections = new();

expandedExpression = _queryableMethodTranslatingExpressionVisitor.ExpandWeakEntities(_queryExpression, expression);
expandedExpression = _queryableMethodTranslatingExpressionVisitor.ExpandSharedTypeEntities(_queryExpression, expression);
result = Visit(expandedExpression);

_queryExpression.ReplaceProjection(_clientProjections);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ namespace Microsoft.EntityFrameworkCore.InMemory.Query.Internal
public class InMemoryQueryableMethodTranslatingExpressionVisitor : QueryableMethodTranslatingExpressionVisitor
{
private readonly InMemoryExpressionTranslatingExpressionVisitor _expressionTranslator;
private readonly WeakEntityExpandingExpressionVisitor _weakEntityExpandingExpressionVisitor;
private readonly SharedTypeEntityExpandingExpressionVisitor _weakEntityExpandingExpressionVisitor;
private readonly InMemoryProjectionBindingExpressionVisitor _projectionBindingExpressionVisitor;
private readonly IModel _model;

Expand All @@ -40,7 +40,7 @@ public InMemoryQueryableMethodTranslatingExpressionVisitor(
: base(dependencies, queryCompilationContext, subquery: false)
{
_expressionTranslator = new InMemoryExpressionTranslatingExpressionVisitor(queryCompilationContext, this);
_weakEntityExpandingExpressionVisitor = new WeakEntityExpandingExpressionVisitor(_expressionTranslator);
_weakEntityExpandingExpressionVisitor = new SharedTypeEntityExpandingExpressionVisitor(_expressionTranslator);
_projectionBindingExpressionVisitor = new InMemoryProjectionBindingExpressionVisitor(this, _expressionTranslator);
_model = queryCompilationContext.Model;
}
Expand All @@ -56,7 +56,7 @@ protected InMemoryQueryableMethodTranslatingExpressionVisitor(
: base(parentVisitor.Dependencies, parentVisitor.QueryCompilationContext, subquery: true)
{
_expressionTranslator = new InMemoryExpressionTranslatingExpressionVisitor(QueryCompilationContext, parentVisitor);
_weakEntityExpandingExpressionVisitor = new WeakEntityExpandingExpressionVisitor(_expressionTranslator);
_weakEntityExpandingExpressionVisitor = new SharedTypeEntityExpandingExpressionVisitor(_expressionTranslator);
_projectionBindingExpressionVisitor = new InMemoryProjectionBindingExpressionVisitor(this, _expressionTranslator);
_model = parentVisitor._model;
}
Expand Down Expand Up @@ -441,7 +441,7 @@ private static ShapedQueryExpression CreateShapedQueryExpressionStatic(IEntityTy
new Expression[] { original1, original2 },
new[] { groupByShaper.KeySelector, groupByShaper }).Visit(resultSelector.Body);

newResultSelectorBody = ExpandWeakEntities(inMemoryQueryExpression, newResultSelectorBody);
newResultSelectorBody = ExpandSharedTypeEntities(inMemoryQueryExpression, newResultSelectorBody);
var newShaper = _projectionBindingExpressionVisitor.Translate(inMemoryQueryExpression, newResultSelectorBody);

return source.UpdateShaperExpression(newShaper);
Expand Down Expand Up @@ -1265,13 +1265,13 @@ private Expression RemapLambdaBody(ShapedQueryExpression shapedQueryExpression,
var lambdaBody = ReplacingExpressionVisitor.Replace(
lambdaExpression.Parameters.Single(), shapedQueryExpression.ShaperExpression, lambdaExpression.Body);

return ExpandWeakEntities((InMemoryQueryExpression)shapedQueryExpression.QueryExpression, lambdaBody);
return ExpandSharedTypeEntities((InMemoryQueryExpression)shapedQueryExpression.QueryExpression, lambdaBody);
}

internal Expression ExpandWeakEntities(InMemoryQueryExpression queryExpression, Expression lambdaBody)
internal Expression ExpandSharedTypeEntities(InMemoryQueryExpression queryExpression, Expression lambdaBody)
=> _weakEntityExpandingExpressionVisitor.Expand(queryExpression, lambdaBody);

private sealed class WeakEntityExpandingExpressionVisitor : ExpressionVisitor
private sealed class SharedTypeEntityExpandingExpressionVisitor : ExpressionVisitor
{
private static readonly MethodInfo _objectEqualsMethodInfo
= typeof(object).GetRequiredRuntimeMethod(nameof(object.Equals), new[] { typeof(object), typeof(object) });
Expand All @@ -1280,7 +1280,7 @@ private static readonly MethodInfo _objectEqualsMethodInfo

private InMemoryQueryExpression _queryExpression;

public WeakEntityExpandingExpressionVisitor(InMemoryExpressionTranslatingExpressionVisitor expressionTranslator)
public SharedTypeEntityExpandingExpressionVisitor(InMemoryExpressionTranslatingExpressionVisitor expressionTranslator)
{
_expressionTranslator = expressionTranslator;
_queryExpression = null!;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static readonly IDictionary<Type, ServiceCharacteristics> RelationalServi
{
{ typeof(IAnnotationCodeGenerator), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IProviderConfigurationCodeGenerator), new ServiceCharacteristics(ServiceLifetime.Singleton) },
{ typeof(IDatabaseModelFactory), new ServiceCharacteristics(ServiceLifetime.Singleton) }
{ typeof(IDatabaseModelFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) }
};

/// <summary>
Expand Down
37 changes: 37 additions & 0 deletions src/EFCore.Relational/Extensions/RelationalModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
using System.Linq;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Internal;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;

// ReSharper disable once CheckNamespace
Expand Down Expand Up @@ -519,5 +521,40 @@ public static void SetCollation(this IMutableModel model, string? value)
/// <returns> The configuration source for the collation. </returns>
public static ConfigurationSource? GetCollationConfigurationSource(this IConventionModel model)
=> model.FindAnnotation(RelationalAnnotationNames.Collation)?.GetConfigurationSource();

/// <summary>
/// Gets the relational database type for a given object, throwing if no mapping is found.
/// </summary>
/// <param name="model"> The model. </param>
/// <param name="value"> The object to get the mapping for. </param>
/// <returns> The type mapping to be used. </returns>
public static RelationalTypeMapping GetMappingForValue(
this IModel model,
object? value)
=> value == null
|| value == DBNull.Value
? RelationalTypeMapping.NullMapping
: model.GetMapping(value.GetType());

/// <summary>
/// Gets the relational database type for a given .NET type, throwing if no mapping is found.
/// </summary>
/// <param name="model"> The model. </param>
/// <param name="clrType"> The type to get the mapping for. </param>
/// <returns> The type mapping to be used. </returns>
public static RelationalTypeMapping GetMapping(
this IModel model,
Type clrType)
{
Check.NotNull(clrType, nameof(clrType));

var mapping = model.FindMapping(clrType);
if (mapping != null)
{
return (RelationalTypeMapping)mapping;
}

throw new InvalidOperationException(RelationalStrings.UnsupportedType(clrType.ShortDisplayName()));
}
}
}
Loading

0 comments on commit d4bb806

Please sign in to comment.