public virtual Func <QueryContext, TResult> CreateQueryExecutor <TResult>([NotNull] Expression query) { Check.NotNull(query, nameof(query)); query = _queryTranslationPreprocessorFactory.Create(this).Process(query); // Convert EntityQueryable to ShapedQueryExpression query = _queryableMethodTranslatingExpressionVisitorFactory.Create(Model).Visit(query); query = _queryTranslationPostprocessorFactory.Create(this).Process(query); // Inject actual entity materializer // Inject tracking query = _shapedQueryCompilingExpressionVisitorFactory.Create(this).Visit(query); // If any additional parameters were added during the compilation phase (e.g. entity equality ID expression), // wrap the query with code adding those parameters to the query context query = InsertRuntimeParameters(query); var queryExecutorExpression = Expression.Lambda <Func <QueryContext, TResult> >( query, QueryContextParameter); try { return(queryExecutorExpression.Compile()); } finally { Logger.QueryExecutionPlanned(new ExpressionPrinter(), queryExecutorExpression); } }
public virtual Func <QueryContext, TResult> CreateQueryExecutor <TResult>(Expression query) { 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); // Inject actual entity materializer // Inject tracking query = _shapedQueryCompilingExpressionVisitorFactory.Create(this).Visit(query); var queryExecutorExpression = Expression.Lambda <Func <QueryContext, TResult> >( query, QueryContextParameter); try { return(queryExecutorExpression.Compile()); } finally { Logger.QueryExecutionPlanned(new ExpressionPrinter(), queryExecutorExpression); } }
/// <summary> /// parse select statement of queryable /// </summary> /// <typeparam name="TEntity"></typeparam> /// <param name="queryable"></param> /// <param name="ctx"></param> /// <returns></returns> public static SelectParsingResult Parse <TEntity>(this IQueryable <TEntity> queryable, DbContext ctx, bool ignoreQueryFilters) where TEntity : class { if (ignoreQueryFilters) { queryable = queryable.IgnoreQueryFilters(); } SelectParsingResult parsingResult = new SelectParsingResult(); Expression query = queryable.Expression; var databaseDependencies = ctx.GetService <DatabaseDependencies>(); IQueryTranslationPreprocessorFactory _queryTranslationPreprocessorFactory = ctx.GetService <IQueryTranslationPreprocessorFactory>(); IQueryableMethodTranslatingExpressionVisitorFactory _queryableMethodTranslatingExpressionVisitorFactory = ctx.GetService <IQueryableMethodTranslatingExpressionVisitorFactory>(); IQueryTranslationPostprocessorFactory _queryTranslationPostprocessorFactory = ctx.GetService <IQueryTranslationPostprocessorFactory>(); QueryCompilationContext queryCompilationContext = databaseDependencies.QueryCompilationContextFactory.Create(true); IDiagnosticsLogger <DbLoggerCategory.Query> logger = ctx.GetService <IDiagnosticsLogger <DbLoggerCategory.Query> >(); QueryContext queryContext = ctx.GetService <IQueryContextFactory>().Create(); QueryCompiler queryComipler = ctx.GetService <IQueryCompiler>() as QueryCompiler; //parameterize determines if it will use "Declare" or not MethodCallExpression methodCallExpr1 = queryComipler.ExtractParameters(query, queryContext, logger, parameterize: true) as MethodCallExpression; QueryTranslationPreprocessor queryTranslationPreprocessor = _queryTranslationPreprocessorFactory.Create(queryCompilationContext); MethodCallExpression methodCallExpr2 = queryTranslationPreprocessor.Process(methodCallExpr1) as MethodCallExpression; QueryableMethodTranslatingExpressionVisitor queryableMethodTranslatingExpressionVisitor = _queryableMethodTranslatingExpressionVisitorFactory.Create(queryCompilationContext); ShapedQueryExpression shapedQueryExpression1 = queryableMethodTranslatingExpressionVisitor.Visit(methodCallExpr2) as ShapedQueryExpression; QueryTranslationPostprocessor queryTranslationPostprocessor = _queryTranslationPostprocessorFactory.Create(queryCompilationContext); ShapedQueryExpression shapedQueryExpression2 = queryTranslationPostprocessor.Process(shapedQueryExpression1) as ShapedQueryExpression; IRelationalParameterBasedSqlProcessorFactory _relationalParameterBasedSqlProcessorFactory = ctx.GetService <IRelationalParameterBasedSqlProcessorFactory>(); RelationalParameterBasedSqlProcessor _relationalParameterBasedSqlProcessor = _relationalParameterBasedSqlProcessorFactory.Create(true); SelectExpression selectExpression = (SelectExpression)shapedQueryExpression2.QueryExpression; selectExpression = _relationalParameterBasedSqlProcessor.Optimize(selectExpression, queryContext.ParameterValues, out bool canCache); IQuerySqlGeneratorFactory querySqlGeneratorFactory = ctx.GetService <IQuerySqlGeneratorFactory>(); IZackQuerySqlGenerator querySqlGenerator = querySqlGeneratorFactory.Create() as IZackQuerySqlGenerator; if (querySqlGenerator == null) { throw new InvalidOperationException("please add dbContext.UseBatchEF() to OnConfiguring first!"); } querySqlGenerator.IsForBatchEF = true; querySqlGenerator.GetCommand(selectExpression); parsingResult.Parameters = queryContext.ParameterValues; parsingResult.PredicateSQL = querySqlGenerator.PredicateSQL; parsingResult.ProjectionSQL = querySqlGenerator.ProjectionSQL; TableExpression tableExpression = selectExpression.Tables[0] as TableExpression; parsingResult.TableName = tableExpression.Table.Name; return(parsingResult); }
public virtual Func <QueryContext, TResult> CreateQueryExecutor <TResult>(Expression query) { 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); // Inject actual entity materializer // Inject tracking query = _shapedQueryCompilingExpressionVisitorFactory.Create(this).Visit(query); return(Expression.Lambda <Func <QueryContext, TResult> >( query, QueryContextParameter) .Compile()); }
protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { if (methodCallExpression.Method.IsEFPropertyMethod()) { var firstArgument = methodCallExpression.Arguments[0]; // In certain cases EF.Property would have convert node around the source. if (firstArgument is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert && unaryExpression.Type == typeof(object)) { firstArgument = unaryExpression.Operand; } if (firstArgument is EntityShaperExpression entityShaper) { return(BindProperty(entityShaper, (string)((ConstantExpression)methodCallExpression.Arguments[1]).Value)); } else { throw new InvalidOperationException(); } } if (methodCallExpression.Method.DeclaringType == typeof(Queryable)) { var translation = _queryableMethodTranslatingExpressionVisitorFactory.Create(_model).Visit(methodCallExpression); if (translation is ShapedQueryExpression shapedQuery) { var subquery = (SelectExpression)shapedQuery.QueryExpression; subquery.ApplyProjection(); if (methodCallExpression.Method.Name == nameof(Queryable.Any) || methodCallExpression.Method.Name == nameof(Queryable.All) || methodCallExpression.Method.Name == nameof(Queryable.Contains)) { if (subquery.Tables.Count == 0 && subquery.Projection.Count == 1) { return(subquery.Projection[0].Expression); } else { throw new InvalidOperationException(); } } else { return(new SubSelectExpression(subquery)); } } else { throw new InvalidOperationException(); } } var @object = (SqlExpression)Visit(methodCallExpression.Object); var failed = TranslationFailed(methodCallExpression.Object, @object); var arguments = new SqlExpression[methodCallExpression.Arguments.Count]; for (var i = 0; i < arguments.Length; i++) { arguments[i] = (SqlExpression)Visit(methodCallExpression.Arguments[i]); failed |= (methodCallExpression.Arguments[i] != null && arguments[i] == null); } return(failed ? null : _methodCallTranslatorProvider.Translate(_model, @object, methodCallExpression.Method, arguments)); }
protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName)) { Type convertedType = null; if (source is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert) { source = unaryExpression.Operand; if (unaryExpression.Type != typeof(object)) { convertedType = unaryExpression.Type; } } if (source is EntityShaperExpression entityShaper) { var entityType = entityShaper.EntityType; if (convertedType != null) { entityType = entityType.RootType().GetDerivedTypesInclusive() .FirstOrDefault(et => et.ClrType == convertedType); } if (entityType != null) { var property = entityType.FindProperty(propertyName); return(BindProperty(entityShaper, property)); } } throw new InvalidOperationException(); } if (methodCallExpression.Method.DeclaringType == typeof(Queryable)) { var translation = _queryableMethodTranslatingExpressionVisitorFactory.Create(_model).Visit(methodCallExpression); if (translation is ShapedQueryExpression shapedQuery) { var subquery = (SelectExpression)shapedQuery.QueryExpression; subquery.ApplyProjection(); if (methodCallExpression.Method.Name == nameof(Queryable.Any) || methodCallExpression.Method.Name == nameof(Queryable.All) || methodCallExpression.Method.Name == nameof(Queryable.Contains)) { if (subquery.Tables.Count == 0 && subquery.Projection.Count == 1) { return(subquery.Projection[0].Expression); } else { throw new InvalidOperationException(); } } else { return(new SubSelectExpression(subquery)); } } else { throw new InvalidOperationException(); } } var @object = (SqlExpression)Visit(methodCallExpression.Object); var failed = TranslationFailed(methodCallExpression.Object, @object); var arguments = new SqlExpression[methodCallExpression.Arguments.Count]; for (var i = 0; i < arguments.Length; i++) { arguments[i] = (SqlExpression)Visit(methodCallExpression.Arguments[i]); failed |= (methodCallExpression.Arguments[i] != null && arguments[i] == null); } return(failed ? null : _methodCallTranslatorProvider.Translate(_model, @object, methodCallExpression.Method, arguments)); }