diff --git a/src/EFCore.Cosmos/Extensions/CosmosServiceCollectionExtensions.cs b/src/EFCore.Cosmos/Extensions/CosmosServiceCollectionExtensions.cs index 17c34e0ba37..17c7fecc9c8 100644 --- a/src/EFCore.Cosmos/Extensions/CosmosServiceCollectionExtensions.cs +++ b/src/EFCore.Cosmos/Extensions/CosmosServiceCollectionExtensions.cs @@ -39,7 +39,6 @@ public static IServiceCollection AddEntityFrameworkCosmos([NotNull] this IServic .TryAdd() // New Query pipeline - .TryAdd() .TryAdd() .TryAdd() diff --git a/src/EFCore.Cosmos/Query/Pipeline/CosmosEntityQueryableTranslatorFactory.cs b/src/EFCore.Cosmos/Query/Pipeline/CosmosEntityQueryableTranslatorFactory.cs deleted file mode 100644 index 88078bdf490..00000000000 --- a/src/EFCore.Cosmos/Query/Pipeline/CosmosEntityQueryableTranslatorFactory.cs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Query.Pipeline; -using Microsoft.EntityFrameworkCore.Storage; - -namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Pipeline -{ - public class CosmosEntityQueryableTranslatorFactory : EntityQueryableTranslatorFactory - { - private readonly IModel _model; - private readonly ISqlExpressionFactory _sqlExpressionFactory; - - public CosmosEntityQueryableTranslatorFactory(IModel model, - ISqlExpressionFactory sqlExpressionFactory) - { - _model = model; - _sqlExpressionFactory = sqlExpressionFactory; - } - - public override EntityQueryableTranslator Create(QueryCompilationContext queryCompilationContext) - { - return new CosmosEntityQueryableTranslator(_model, _sqlExpressionFactory); - } - } - - public class CosmosEntityQueryableTranslator : EntityQueryableTranslator - { - private readonly IModel _model; - private readonly ISqlExpressionFactory _sqlExpressionFactory; - - public CosmosEntityQueryableTranslator(IModel model, - ISqlExpressionFactory sqlExpressionFactory) - { - _model = model; - _sqlExpressionFactory = sqlExpressionFactory; - } - - protected override ShapedQueryExpression CreateShapedQueryExpression(Type elementType) - { - var entityType = _model.FindEntityType(elementType); - var selectExpression = _sqlExpressionFactory.Select(entityType); - - return new ShapedQueryExpression( - selectExpression, - new EntityShaperExpression( - entityType, - new ProjectionBindingExpression( - selectExpression, - new ProjectionMember(), - typeof(ValueBuffer)), - false)); - } - } -} diff --git a/src/EFCore.Cosmos/Query/Pipeline/CosmosQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Cosmos/Query/Pipeline/CosmosQueryableMethodTranslatingExpressionVisitor.cs index 840b307a308..cf1fbb59806 100644 --- a/src/EFCore.Cosmos/Query/Pipeline/CosmosQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Cosmos/Query/Pipeline/CosmosQueryableMethodTranslatingExpressionVisitor.cs @@ -7,11 +7,13 @@ using System.Linq.Expressions; using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Query.Pipeline; +using Microsoft.EntityFrameworkCore.Storage; namespace Microsoft.EntityFrameworkCore.Cosmos.Query.Pipeline { public class CosmosQueryableMethodTranslatingExpressionVisitor : QueryableMethodTranslatingExpressionVisitor { + private readonly IModel _model; private readonly ISqlExpressionFactory _sqlExpressionFactory; private readonly CosmosSqlTranslatingExpressionVisitor _sqlTranslator; private readonly CosmosProjectionBindingExpressionVisitor _projectionBindingExpressionVisitor; @@ -21,7 +23,9 @@ public CosmosQueryableMethodTranslatingExpressionVisitor( ISqlExpressionFactory sqlExpressionFactory, IMemberTranslatorProvider memberTranslatorProvider, IMethodCallTranslatorProvider methodCallTranslatorProvider) + : base(subquery: false) { + _model = model; _sqlExpressionFactory = sqlExpressionFactory; _sqlTranslator = new CosmosSqlTranslatingExpressionVisitor( model, @@ -36,6 +40,22 @@ public override ShapedQueryExpression TranslateSubquery(Expression expression) throw new NotImplementedException(); } + protected override ShapedQueryExpression CreateShapedQueryExpression(Type elementType) + { + var entityType = _model.FindEntityType(elementType); + var selectExpression = _sqlExpressionFactory.Select(entityType); + + return new ShapedQueryExpression( + selectExpression, + new EntityShaperExpression( + entityType, + new ProjectionBindingExpression( + selectExpression, + new ProjectionMember(), + typeof(ValueBuffer)), + false)); + } + protected override ShapedQueryExpression TranslateAll(ShapedQueryExpression source, LambdaExpression predicate) { throw new NotImplementedException(); diff --git a/src/EFCore.InMemory/Extensions/InMemoryServiceCollectionExtensions.cs b/src/EFCore.InMemory/Extensions/InMemoryServiceCollectionExtensions.cs index 51986bcbc0a..06e6c4342eb 100644 --- a/src/EFCore.InMemory/Extensions/InMemoryServiceCollectionExtensions.cs +++ b/src/EFCore.InMemory/Extensions/InMemoryServiceCollectionExtensions.cs @@ -73,7 +73,6 @@ public static IServiceCollection AddEntityFrameworkInMemoryDatabase([NotNull] th // New Query pipeline .TryAdd() .TryAdd() - .TryAdd() .TryAdd() .TryAdd(p => p.GetService()) diff --git a/src/EFCore.InMemory/Query/Pipeline/InMemoryEntityQueryableExpressionVisitorFactory2.cs b/src/EFCore.InMemory/Query/Pipeline/InMemoryEntityQueryableExpressionVisitorFactory2.cs deleted file mode 100644 index c020fe105f7..00000000000 --- a/src/EFCore.InMemory/Query/Pipeline/InMemoryEntityQueryableExpressionVisitorFactory2.cs +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Query.Pipeline; - -namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline -{ - public class InMemoryEntityQueryableTranslatorFactory : EntityQueryableTranslatorFactory - { - private readonly IModel _model; - - public InMemoryEntityQueryableTranslatorFactory(IModel model) - { - _model = model; - } - - public override EntityQueryableTranslator Create(QueryCompilationContext queryCompilationContext) - { - return new InMemoryEntityQueryableTranslator(_model); - } - } -} diff --git a/src/EFCore.InMemory/Query/Pipeline/InMemoryEntityQueryableExpressionVisitors.cs b/src/EFCore.InMemory/Query/Pipeline/InMemoryEntityQueryableExpressionVisitors.cs deleted file mode 100644 index bec251a557f..00000000000 --- a/src/EFCore.InMemory/Query/Pipeline/InMemoryEntityQueryableExpressionVisitors.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq.Expressions; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Query.Pipeline; -using Microsoft.EntityFrameworkCore.Storage; - -namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline -{ - public class InMemoryEntityQueryableTranslator : EntityQueryableTranslator - { - private readonly IModel _model; - - public InMemoryEntityQueryableTranslator(IModel model) - { - _model = model; - } - - protected override ShapedQueryExpression CreateShapedQueryExpression(Type elementType) - { - var entityType = _model.FindEntityType(elementType); - var queryExpression = new InMemoryQueryExpression(entityType); - - return new ShapedQueryExpression( - queryExpression, - new EntityShaperExpression( - entityType, - new ProjectionBindingExpression( - queryExpression, - new ProjectionMember(), - typeof(ValueBuffer)), - false)); - } - } -} diff --git a/src/EFCore.InMemory/Query/Pipeline/InMemoryQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.InMemory/Query/Pipeline/InMemoryQueryableMethodTranslatingExpressionVisitor.cs index f5d73838733..f8d42811c9a 100644 --- a/src/EFCore.InMemory/Query/Pipeline/InMemoryQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.InMemory/Query/Pipeline/InMemoryQueryableMethodTranslatingExpressionVisitor.cs @@ -5,6 +5,7 @@ using System.Linq; using System.Linq.Expressions; using System.Reflection; +using Microsoft.EntityFrameworkCore.Metadata; using Microsoft.EntityFrameworkCore.Query.Pipeline; using Microsoft.EntityFrameworkCore.Storage; @@ -14,11 +15,14 @@ public class InMemoryQueryableMethodTranslatingExpressionVisitor : QueryableMeth { private readonly InMemoryExpressionTranslatingExpressionVisitor _expressionTranslator; private readonly InMemoryProjectionBindingExpressionVisitor _projectionBindingExpressionVisitor; + private readonly IModel _model; - public InMemoryQueryableMethodTranslatingExpressionVisitor() + public InMemoryQueryableMethodTranslatingExpressionVisitor(IModel model) + : base(subquery: false) { _expressionTranslator = new InMemoryExpressionTranslatingExpressionVisitor(); _projectionBindingExpressionVisitor = new InMemoryProjectionBindingExpressionVisitor(_expressionTranslator); + _model = model; } public override ShapedQueryExpression TranslateSubquery(Expression expression) @@ -26,6 +30,22 @@ public override ShapedQueryExpression TranslateSubquery(Expression expression) throw new NotImplementedException(); } + protected override ShapedQueryExpression CreateShapedQueryExpression(Type elementType) + { + var entityType = _model.FindEntityType(elementType); + var queryExpression = new InMemoryQueryExpression(entityType); + + return new ShapedQueryExpression( + queryExpression, + new EntityShaperExpression( + entityType, + new ProjectionBindingExpression( + queryExpression, + new ProjectionMember(), + typeof(ValueBuffer)), + false)); + } + protected override ShapedQueryExpression TranslateAll(ShapedQueryExpression source, LambdaExpression predicate) { var inMemoryQueryExpression = (InMemoryQueryExpression)source.QueryExpression; diff --git a/src/EFCore.InMemory/Query/Pipeline/InMemoryQueryableMethodTranslatingExpressionVisitorFactory.cs b/src/EFCore.InMemory/Query/Pipeline/InMemoryQueryableMethodTranslatingExpressionVisitorFactory.cs index c0ffefc04d6..8a19cb997fe 100644 --- a/src/EFCore.InMemory/Query/Pipeline/InMemoryQueryableMethodTranslatingExpressionVisitorFactory.cs +++ b/src/EFCore.InMemory/Query/Pipeline/InMemoryQueryableMethodTranslatingExpressionVisitorFactory.cs @@ -10,7 +10,7 @@ public class InMemoryQueryableMethodTranslatingExpressionVisitorFactory : IQuery { public QueryableMethodTranslatingExpressionVisitor Create(IModel model) { - return new InMemoryQueryableMethodTranslatingExpressionVisitor(); + return new InMemoryQueryableMethodTranslatingExpressionVisitor(model); } } } diff --git a/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs b/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs index da4f4013d8c..d998917eff4 100644 --- a/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs +++ b/src/EFCore.Relational/Infrastructure/EntityFrameworkRelationalServicesBuilder.cs @@ -168,7 +168,6 @@ public override EntityFrameworkServicesBuilder TryAddCoreServices() TryAdd(); TryAdd(); TryAdd(); - TryAdd(); TryAdd(); TryAdd(); TryAdd(); diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalEntityQueryableExpressionVisitorFactory2.cs b/src/EFCore.Relational/Query/Pipeline/RelationalEntityQueryableExpressionVisitorFactory2.cs deleted file mode 100644 index 9e8be03066d..00000000000 --- a/src/EFCore.Relational/Query/Pipeline/RelationalEntityQueryableExpressionVisitorFactory2.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Query.Pipeline; - -namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline -{ - public class RelationalEntityQueryableTranslatorFactory : EntityQueryableTranslatorFactory - { - private readonly IModel _model; - private readonly ISqlExpressionFactory _sqlExpressionFactory; - - public RelationalEntityQueryableTranslatorFactory(IModel model, ISqlExpressionFactory sqlExpressionFactory) - { - _model = model; - _sqlExpressionFactory = sqlExpressionFactory; - } - - public override EntityQueryableTranslator Create(QueryCompilationContext queryCompilationContext) - { - return new RelationalEntityQueryableTranslator(_model, _sqlExpressionFactory); - } - } -} diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalEntityQueryableExpressionVisitors.cs b/src/EFCore.Relational/Query/Pipeline/RelationalEntityQueryableExpressionVisitors.cs deleted file mode 100644 index 1b9e728bf19..00000000000 --- a/src/EFCore.Relational/Query/Pipeline/RelationalEntityQueryableExpressionVisitors.cs +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Linq.Expressions; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Query.Pipeline; -using Microsoft.EntityFrameworkCore.Relational.Query.Pipeline.SqlExpressions; -using Microsoft.EntityFrameworkCore.Storage; - -namespace Microsoft.EntityFrameworkCore.Relational.Query.Pipeline -{ - public class RelationalEntityQueryableTranslator : EntityQueryableTranslator - { - private readonly IModel _model; - private readonly ISqlExpressionFactory _sqlExpressionFactory; - - public RelationalEntityQueryableTranslator(IModel model, ISqlExpressionFactory sqlExpressionFactory) - { - _model = model; - _sqlExpressionFactory = sqlExpressionFactory; - } - - protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) - { - if (methodCallExpression.Method.DeclaringType == typeof(RelationalQueryableExtensions) - && methodCallExpression.Method.Name == nameof(RelationalQueryableExtensions.FromSqlOnQueryable)) - { - var sql = (string)((ConstantExpression)methodCallExpression.Arguments[1]).Value; - var queryable = (IQueryable)((ConstantExpression)methodCallExpression.Arguments[0]).Value; - return CreateShapedQueryExpression(queryable.ElementType, sql, methodCallExpression.Arguments[2]); - } - - return base.VisitMethodCall(methodCallExpression); - } - - protected override ShapedQueryExpression CreateShapedQueryExpression(Type elementType) - { - var entityType = _model.FindEntityType(elementType); - var queryExpression = _sqlExpressionFactory.Select(entityType); - - return CreateShapedQueryExpression(entityType, queryExpression); - } - - protected virtual ShapedQueryExpression CreateShapedQueryExpression(Type elementType, string sql, Expression arguments) - { - var entityType = _model.FindEntityType(elementType); - var queryExpression = _sqlExpressionFactory.Select(entityType, sql, arguments); - - return CreateShapedQueryExpression(entityType, queryExpression); - } - - private ShapedQueryExpression CreateShapedQueryExpression(IEntityType entityType, SelectExpression selectExpression) - { - return new ShapedQueryExpression( - selectExpression, - new EntityShaperExpression( - entityType, - new ProjectionBindingExpression( - selectExpression, - new ProjectionMember(), - typeof(ValueBuffer)), - false)); - } - } -} diff --git a/src/EFCore.Relational/Query/Pipeline/RelationalQueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore.Relational/Query/Pipeline/RelationalQueryableMethodTranslatingExpressionVisitor.cs index 65e66e1ee95..e91433977b2 100644 --- a/src/EFCore.Relational/Query/Pipeline/RelationalQueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore.Relational/Query/Pipeline/RelationalQueryableMethodTranslatingExpressionVisitor.cs @@ -28,6 +28,7 @@ public RelationalQueryableMethodTranslatingExpressionVisitor( IModel model, IRelationalSqlTranslatingExpressionVisitorFactory relationalSqlTranslatingExpressionVisitorFactory, ISqlExpressionFactory sqlExpressionFactory) + : base(subquery: false) { _sqlTranslator = relationalSqlTranslatingExpressionVisitorFactory.Create(model, this); _projectionBindingExpressionVisitor = new RelationalProjectionBindingExpressionVisitor(this, _sqlTranslator); @@ -39,6 +40,7 @@ private RelationalQueryableMethodTranslatingExpressionVisitor( IModel model, RelationalSqlTranslatingExpressionVisitor sqlTranslator, ISqlExpressionFactory sqlExpressionFactory) + : base(subquery: true) { _model = model; _sqlTranslator = sqlTranslator; @@ -46,6 +48,19 @@ private RelationalQueryableMethodTranslatingExpressionVisitor( _sqlExpressionFactory = sqlExpressionFactory; } + protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) + { + if (methodCallExpression.Method.DeclaringType == typeof(RelationalQueryableExtensions) + && methodCallExpression.Method.Name == nameof(RelationalQueryableExtensions.FromSqlOnQueryable)) + { + var sql = (string)((ConstantExpression)methodCallExpression.Arguments[1]).Value; + var queryable = (IQueryable)((ConstantExpression)methodCallExpression.Arguments[0]).Value; + return CreateShapedQueryExpression(queryable.ElementType, sql, methodCallExpression.Arguments[2]); + } + + return base.VisitMethodCall(methodCallExpression); + } + public override ShapedQueryExpression TranslateSubquery(Expression expression) { return (ShapedQueryExpression)new RelationalQueryableMethodTranslatingExpressionVisitor( @@ -55,6 +70,35 @@ public override ShapedQueryExpression TranslateSubquery(Expression expression) } + protected override ShapedQueryExpression CreateShapedQueryExpression(Type elementType) + { + var entityType = _model.FindEntityType(elementType); + var queryExpression = _sqlExpressionFactory.Select(entityType); + + return CreateShapedQueryExpression(entityType, queryExpression); + } + + private ShapedQueryExpression CreateShapedQueryExpression(Type elementType, string sql, Expression arguments) + { + var entityType = _model.FindEntityType(elementType); + var queryExpression = _sqlExpressionFactory.Select(entityType, sql, arguments); + + return CreateShapedQueryExpression(entityType, queryExpression); + } + + private ShapedQueryExpression CreateShapedQueryExpression(IEntityType entityType, SelectExpression selectExpression) + { + return new ShapedQueryExpression( + selectExpression, + new EntityShaperExpression( + entityType, + new ProjectionBindingExpression( + selectExpression, + new ProjectionMember(), + typeof(ValueBuffer)), + false)); + } + protected override ShapedQueryExpression TranslateAll(ShapedQueryExpression source, LambdaExpression predicate) { var translation = TranslateLambdaExpression(source, predicate); diff --git a/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs b/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs index 45dba7de07b..98df6e952f4 100644 --- a/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs +++ b/src/EFCore/Infrastructure/EntityFrameworkServicesBuilder.cs @@ -136,7 +136,6 @@ public static readonly IDictionary CoreServices // New Query related services { typeof(IQueryCompilationContextFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) }, { typeof(IQueryOptimizerFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) }, - { typeof(IEntityQueryableTranslatorFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) }, { typeof(IQueryableMethodTranslatingExpressionVisitorFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) }, { typeof(IShapedQueryOptimizerFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) }, { typeof(IShapedQueryCompilingExpressionVisitorFactory), new ServiceCharacteristics(ServiceLifetime.Scoped) }, diff --git a/src/EFCore/Query/Pipeline/EntityQueryableExpressionVisitors.cs b/src/EFCore/Query/Pipeline/EntityQueryableExpressionVisitors.cs deleted file mode 100644 index baf50563827..00000000000 --- a/src/EFCore/Query/Pipeline/EntityQueryableExpressionVisitors.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using System.Linq; -using System.Linq.Expressions; -using Microsoft.EntityFrameworkCore.Internal; - -namespace Microsoft.EntityFrameworkCore.Query.Pipeline -{ - public abstract class EntityQueryableTranslator : ExpressionVisitor - { - protected override Expression VisitConstant(ConstantExpression constantExpression) - => constantExpression.IsEntityQueryable() - ? CreateShapedQueryExpression(((IQueryable)constantExpression.Value).ElementType) - : base.VisitConstant(constantExpression); - - protected abstract ShapedQueryExpression CreateShapedQueryExpression(Type elementType); - } -} diff --git a/src/EFCore/Query/Pipeline/EntityQueryableExpressionVisitorsFactory.cs b/src/EFCore/Query/Pipeline/EntityQueryableExpressionVisitorsFactory.cs deleted file mode 100644 index c205e9a7899..00000000000 --- a/src/EFCore/Query/Pipeline/EntityQueryableExpressionVisitorsFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.EntityFrameworkCore.Query.Pipeline -{ - public abstract class EntityQueryableTranslatorFactory : IEntityQueryableTranslatorFactory - { - public abstract EntityQueryableTranslator Create(QueryCompilationContext queryCompilationContext); - } -} diff --git a/src/EFCore/Query/Pipeline/IEntityQueryableExpressionVisitorsFactory.cs b/src/EFCore/Query/Pipeline/IEntityQueryableExpressionVisitorsFactory.cs deleted file mode 100644 index aa6e8a6ab7b..00000000000 --- a/src/EFCore/Query/Pipeline/IEntityQueryableExpressionVisitorsFactory.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -namespace Microsoft.EntityFrameworkCore.Query.Pipeline -{ - public interface IEntityQueryableTranslatorFactory - { - EntityQueryableTranslator Create(QueryCompilationContext queryCompilationContext); - } -} diff --git a/src/EFCore/Query/Pipeline/QueryCompilationContext.cs b/src/EFCore/Query/Pipeline/QueryCompilationContext.cs index 2ca26ad1a32..067076c4481 100644 --- a/src/EFCore/Query/Pipeline/QueryCompilationContext.cs +++ b/src/EFCore/Query/Pipeline/QueryCompilationContext.cs @@ -15,7 +15,6 @@ public class QueryCompilationContext public static readonly ParameterExpression QueryContextParameter = Expression.Parameter(typeof(QueryContext), "queryContext"); private readonly IQueryOptimizerFactory _queryOptimizerFactory; - private readonly IEntityQueryableTranslatorFactory _entityQueryableTranslatorFactory; private readonly IQueryableMethodTranslatingExpressionVisitorFactory _queryableMethodTranslatingExpressionVisitorFactory; private readonly IShapedQueryOptimizerFactory _shapedQueryOptimizerFactory; private readonly IShapedQueryCompilingExpressionVisitorFactory _shapedQueryCompilingExpressionVisitorFactory; @@ -23,7 +22,6 @@ public class QueryCompilationContext public QueryCompilationContext( IModel model, IQueryOptimizerFactory queryOptimizerFactory, - IEntityQueryableTranslatorFactory entityQuerableTranslatorFactory, IQueryableMethodTranslatingExpressionVisitorFactory queryableMethodTranslatingExpressionVisitorFactory, IShapedQueryOptimizerFactory shapedQueryOptimizerFactory, IShapedQueryCompilingExpressionVisitorFactory shapedQueryCompilingExpressionVisitorFactory, @@ -40,7 +38,6 @@ public QueryCompilationContext( Logger = logger; _queryOptimizerFactory = queryOptimizerFactory; - _entityQueryableTranslatorFactory = entityQuerableTranslatorFactory; _queryableMethodTranslatingExpressionVisitorFactory = queryableMethodTranslatingExpressionVisitorFactory; _shapedQueryOptimizerFactory = shapedQueryOptimizerFactory; _shapedQueryCompilingExpressionVisitorFactory = shapedQueryCompilingExpressionVisitorFactory; @@ -58,7 +55,6 @@ public virtual Func CreateQueryExecutor(Expressi { query = _queryOptimizerFactory.Create(this).Visit(query); // Convert EntityQueryable to ShapedQueryExpression - query = _entityQueryableTranslatorFactory.Create(this).Visit(query); query = _queryableMethodTranslatingExpressionVisitorFactory.Create(Model).Visit(query); query = _shapedQueryOptimizerFactory.Create(this).Visit(query); diff --git a/src/EFCore/Query/Pipeline/QueryCompilationContextFactory.cs b/src/EFCore/Query/Pipeline/QueryCompilationContextFactory.cs index 5d4dc34e5e4..a4d26f44b55 100644 --- a/src/EFCore/Query/Pipeline/QueryCompilationContextFactory.cs +++ b/src/EFCore/Query/Pipeline/QueryCompilationContextFactory.cs @@ -11,7 +11,6 @@ public class QueryCompilationContextFactory : IQueryCompilationContextFactory { private readonly IModel _model; private readonly IQueryOptimizerFactory _queryOptimizerFactory; - private readonly IEntityQueryableTranslatorFactory _entityQueryableTranslatorFactory; private readonly IQueryableMethodTranslatingExpressionVisitorFactory _queryableMethodTranslatingExpressionVisitorFactory; private readonly IShapedQueryOptimizerFactory _shapedQueryOptimizerFactory; private readonly IShapedQueryCompilingExpressionVisitorFactory _shapedQueryCompilingExpressionVisitorFactory; @@ -22,7 +21,6 @@ public class QueryCompilationContextFactory : IQueryCompilationContextFactory public QueryCompilationContextFactory( IModel model, IQueryOptimizerFactory queryOptimizerFactory, - IEntityQueryableTranslatorFactory entityQueryableTranslatorFactory, IQueryableMethodTranslatingExpressionVisitorFactory queryableMethodTranslatingExpressionVisitorFactory, IShapedQueryOptimizerFactory shapedQueryOptimizerFactory, IShapedQueryCompilingExpressionVisitorFactory shapedQueryCompilingExpressionVisitorFactory, @@ -32,7 +30,6 @@ public QueryCompilationContextFactory( { _model = model; _queryOptimizerFactory = queryOptimizerFactory; - _entityQueryableTranslatorFactory = entityQueryableTranslatorFactory; _queryableMethodTranslatingExpressionVisitorFactory = queryableMethodTranslatingExpressionVisitorFactory; _shapedQueryOptimizerFactory = shapedQueryOptimizerFactory; _shapedQueryCompilingExpressionVisitorFactory = shapedQueryCompilingExpressionVisitorFactory; @@ -46,7 +43,6 @@ public QueryCompilationContext Create(bool async) var queryCompilationContext = new QueryCompilationContext( _model, _queryOptimizerFactory, - _entityQueryableTranslatorFactory, _queryableMethodTranslatingExpressionVisitorFactory, _shapedQueryOptimizerFactory, _shapedQueryCompilingExpressionVisitorFactory, diff --git a/src/EFCore/Query/Pipeline/QueryableMethodTranslatingExpressionVisitor.cs b/src/EFCore/Query/Pipeline/QueryableMethodTranslatingExpressionVisitor.cs index 57781cc1a3d..53128597429 100644 --- a/src/EFCore/Query/Pipeline/QueryableMethodTranslatingExpressionVisitor.cs +++ b/src/EFCore/Query/Pipeline/QueryableMethodTranslatingExpressionVisitor.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using System.Reflection; @@ -14,16 +13,18 @@ namespace Microsoft.EntityFrameworkCore.Query.Pipeline { public abstract class QueryableMethodTranslatingExpressionVisitor : ExpressionVisitor { - protected override Expression VisitExtension(Expression extensionExpression) - { - if (extensionExpression is ShapedQueryExpression) - { - return extensionExpression; - } + private readonly bool _subquery; - return base.VisitExtension(extensionExpression); + protected QueryableMethodTranslatingExpressionVisitor(bool subquery) + { + _subquery = subquery; } + protected override Expression VisitConstant(ConstantExpression constantExpression) + => constantExpression.IsEntityQueryable() + ? CreateShapedQueryExpression(((IQueryable)constantExpression.Value).ElementType) + : base.VisitConstant(constantExpression); + protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { if (methodCallExpression.Method.DeclaringType == typeof(Queryable) @@ -430,8 +431,6 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp break; } } - - throw new NotImplementedException("Unhandled method: " + methodCallExpression.Method.Name); } // TODO: Skip ToOrderedQueryable method. See Issue#15591 @@ -441,7 +440,9 @@ protected override Expression VisitMethodCall(MethodCallExpression methodCallExp return Visit(methodCallExpression.Arguments[0]); } - return base.VisitMethodCall(methodCallExpression); + return _subquery + ? (Expression)null + : throw new NotImplementedException("Unhandled method: " + methodCallExpression.Method.Name); } protected Type CreateTransparentIdentifierType(Type outerType, Type innerType) @@ -565,6 +566,7 @@ private static Expression AccessInnerTransparentField( return Expression.Field(targetExpression, fieldInfo); } + protected abstract ShapedQueryExpression CreateShapedQueryExpression(Type elementType); protected abstract ShapedQueryExpression TranslateAll(ShapedQueryExpression source, LambdaExpression predicate); protected abstract ShapedQueryExpression TranslateAny(ShapedQueryExpression source, LambdaExpression predicate); protected abstract ShapedQueryExpression TranslateAverage(ShapedQueryExpression source, LambdaExpression selector, Type resultType); @@ -602,7 +604,6 @@ private static Expression AccessInnerTransparentField( protected abstract ShapedQueryExpression TranslateUnion(ShapedQueryExpression source1, ShapedQueryExpression source2); protected abstract ShapedQueryExpression TranslateWhere(ShapedQueryExpression source, LambdaExpression predicate); public abstract ShapedQueryExpression TranslateSubquery(Expression expression); - } public readonly struct TransparentIdentifier