예제 #1
0
        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);
            }
        }
예제 #2
0
        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());
        }
예제 #5
0
        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));
        }
예제 #6
0
        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));
        }