Пример #1
0
        /// <summary>
        ///     Parses the passes query parameters to a <see cref="ModelFilter{T}" />.
        /// </summary>
        /// <param name="queryParameters"></param>
        /// <returns></returns>
        public IModelFilter <T> Parse(NameValueCollection queryParameters)
        {
            var orderbyField     = queryParameters[StringConstants.OrderByParameter];
            var selects          = queryParameters[StringConstants.SelectParameter];
            var filter           = queryParameters[StringConstants.FilterParameter];
            var skip             = queryParameters[StringConstants.SkipParameter];
            var top              = queryParameters[StringConstants.TopParameter];
            var inlineCount      = queryParameters[StringConstants.InlineCount];
            var includeCount     = !string.IsNullOrWhiteSpace(inlineCount) || inlineCount == "allpages";
            var filterExpression = _filterExpressionFactory.Create <T>(filter);
            var sortDescriptions = _sortExpressionFactory.Create <T>(orderbyField);
            var selectFunction   = _selectExpressionFactory.Create(selects);

            return(new ModelFilter <T>(filterExpression, selectFunction, sortDescriptions,
                                       string.IsNullOrWhiteSpace(skip) ? -1 : Convert.ToInt32(skip),
                                       string.IsNullOrWhiteSpace(top) ? -1 : Convert.ToInt32(top), includeCount));
        }
Пример #2
0
        /// <summary>
        /// Parses the passes query parameters to a <see cref="ModelFilter{T}"/>.
        /// </summary>
        /// <param name="queryParameters"></param>
        /// <returns></returns>
        public IModelFilter <T> Parse(NameValueCollection queryParameters)
        {
            var orderbyField = queryParameters[StringConstants.OrderByParameter];
            var selects      = queryParameters[StringConstants.SelectParameter];
            var filter       = queryParameters[StringConstants.FilterParameter];
            var skip         = queryParameters[StringConstants.SkipParameter];
            var top          = queryParameters[StringConstants.TopParameter];

            var filterExpression = m_filterExpressionFactory.Create <T>(filter);
            var sortDescriptions = m_sortExpressionFactory.Create <T>(orderbyField);
            var selectFunction   = m_selectExpressionFactory.Create(selects);

            var modelFilter = new ModelFilter <T>(
                filterExpression,
                selectFunction,
                sortDescriptions,
                skip.IsNullOrWhiteSpace() ? -1 : Convert.ToInt32(skip),
                top.IsNullOrWhiteSpace() ? -1 : Convert.ToInt32(top));

            return(modelFilter);
        }
Пример #3
0
        /// <summary>
        /// Parses the passes query parameters to a <see cref="ModelFilter{T}"/>.
        /// </summary>
        /// <param name="queryParameters"></param>
        /// <returns></returns>
        public IModelFilter <T> Parse(IEnumerable <KeyValuePair <string, string> > queryParameters)
        {
            var orderbyField = queryParameters.GetValue(StringConstants.OrderByParameter).FirstOrDefault();
            var selects      = queryParameters.GetValue(StringConstants.SelectParameter).FirstOrDefault();
            var filter       = queryParameters.GetValue(StringConstants.FilterParameter).FirstOrDefault();
            var skip         = queryParameters.GetValue(StringConstants.SkipParameter).FirstOrDefault();
            var top          = queryParameters.GetValue(StringConstants.TopParameter).FirstOrDefault();

            var filterExpression = _filterExpressionFactory.Create <T>(filter);
            var sortDescriptions = _sortExpressionFactory.Create <T>(orderbyField);
            var selectFunction   = _selectExpressionFactory.Create(selects);

            var modelFilter = new ModelFilter <T>(
                _settings,
                filterExpression,
                selectFunction,
                sortDescriptions,
                string.IsNullOrWhiteSpace(skip) ? -1 : Convert.ToInt32(skip),
                string.IsNullOrWhiteSpace(top) ? -1 : Convert.ToInt32(top));

            return(modelFilter);
        }
Пример #4
0
        private IReadOnlyList <Func <QueryContext, TRelatedEntitiesLoader> > CreateRelatedEntitiesLoaders <TRelatedEntitiesLoader>(
            IQuerySource querySource, IEnumerable <INavigation> navigationPath)
        {
            var relatedEntitiesLoaders = new List <Func <QueryContext, TRelatedEntitiesLoader> >();

            var selectExpression
                = _queryCompilationContext.FindSelectExpression(querySource);

            var compositePredicateExpressionVisitor
                = _compositePredicateExpressionVisitorFactory.Create();

            var targetTableExpression
                = selectExpression.GetTableForQuerySource(querySource);

            var canProduceInnerJoin = true;
            var navigationCount     = 0;

            foreach (var navigation in navigationPath)
            {
                var queryIndex = _queryIndexes[navigationCount];
                navigationCount++;

                var targetEntityType = navigation.GetTargetType();
                var targetTableName  = _relationalAnnotationProvider.For(targetEntityType).TableName;
                var targetTableAlias
                    = _queryCompilationContext
                      .CreateUniqueTableAlias(targetTableName[0].ToString().ToLowerInvariant());

                if (!navigation.IsCollection())
                {
                    var joinedTableExpression
                        = new TableExpression(
                              targetTableName,
                              _relationalAnnotationProvider.For(targetEntityType).Schema,
                              targetTableAlias,
                              querySource);

                    var valueBufferOffset = selectExpression.Projection.Count;

                    canProduceInnerJoin
                        = canProduceInnerJoin &&
                          navigation.ForeignKey.IsRequired &&
                          navigation.IsDependentToPrincipal();

                    var joinExpression
                        = canProduceInnerJoin
                            ? selectExpression.AddInnerJoin(joinedTableExpression)
                            : selectExpression.AddLeftOuterJoin(joinedTableExpression);

                    var oldPredicate = selectExpression.Predicate;

                    var materializer
                        = _materializerFactory
                          .CreateMaterializer(
                              targetEntityType,
                              selectExpression,
                              (p, se) => se.AddToProjection(
                                  new AliasExpression(
                                      new ColumnExpression(
                                          _relationalAnnotationProvider.For(p).ColumnName,
                                          p,
                                          joinedTableExpression))) - valueBufferOffset,
                              querySource: null);

                    if (selectExpression.Predicate != oldPredicate)
                    {
                        selectExpression.Predicate
                            = compositePredicateExpressionVisitor
                              .Visit(selectExpression.Predicate);

                        var newJoinExpression = AdjustJoinExpression(selectExpression, joinExpression);

                        selectExpression.Predicate = oldPredicate;
                        selectExpression.RemoveTable(joinExpression);
                        selectExpression.AddTable(newJoinExpression, createUniqueAlias: false);
                        joinExpression = newJoinExpression;
                    }

                    joinExpression.Predicate
                        = BuildJoinEqualityExpression(
                              navigation,
                              navigation.IsDependentToPrincipal() ? targetTableExpression : joinExpression,
                              navigation.IsDependentToPrincipal() ? joinExpression : targetTableExpression,
                              querySource);

                    targetTableExpression = joinedTableExpression;

                    relatedEntitiesLoaders.Add(qc =>
                                               (TRelatedEntitiesLoader)_queryCompilationContext.QueryMethodProvider
                                               .CreateReferenceRelatedEntitiesLoaderMethod
                                               .Invoke(
                                                   null,
                                                   new object[]
                    {
                        valueBufferOffset,
                        queryIndex,
                        materializer.Compile()             // TODO: Used cached materializer?
                    }));
                }
                else
                {
                    var principalTable
                        = selectExpression.Tables.Count == 1 &&
                          selectExpression.Tables
                          .OfType <SelectExpression>()
                          .Any(s => s.Tables.Any(t => t.QuerySource == querySource))
                          // true when select is wrapped e.g. when RowNumber paging is enabled
                            ? selectExpression.Tables[0]
                            : selectExpression.Tables.Last(t => t.QuerySource == querySource);

                    var canGenerateExists
                        = (selectExpression.Predicate != null ||
                           selectExpression.Offset == null) &&
                          !IsOrderingOnNonPrincipalKeyProperties(
                              selectExpression.OrderBy,
                              navigation.ForeignKey.PrincipalKey.Properties);

                    foreach (var property in navigation.ForeignKey.PrincipalKey.Properties)
                    {
                        selectExpression
                        .AddToOrderBy(
                            _relationalAnnotationProvider.For(property).ColumnName,
                            property,
                            principalTable,
                            OrderingDirection.Asc);
                    }

                    var targetSelectExpression = _selectExpressionFactory.Create(_queryCompilationContext);

                    targetTableExpression
                        = new TableExpression(
                              targetTableName,
                              _relationalAnnotationProvider.For(targetEntityType).Schema,
                              targetTableAlias,
                              querySource);

                    targetSelectExpression.AddTable(targetTableExpression, createUniqueAlias: false);

                    var materializer
                        = _materializerFactory
                          .CreateMaterializer(
                              targetEntityType,
                              targetSelectExpression,
                              (p, se) => se.AddToProjection(
                                  _relationalAnnotationProvider.For(p).ColumnName,
                                  p,
                                  querySource),
                              querySource: null);

                    if (canGenerateExists)
                    {
                        var subqueryExpression = selectExpression.Clone();
                        subqueryExpression.ClearProjection();
                        subqueryExpression.ClearOrderBy();
                        subqueryExpression.IsProjectStar = false;

                        var subqueryTable
                            = subqueryExpression.Tables.Count == 1 &&
                              subqueryExpression.Tables
                              .OfType <SelectExpression>()
                              .Any(s => s.Tables.Any(t => t.QuerySource == querySource))
                              // true when select is wrapped e.g. when RowNumber paging is enabled
                                ? subqueryExpression.Tables[0]
                                : subqueryExpression.Tables.Last(t => t.QuerySource == querySource);

                        var existsPredicateExpression = new ExistsExpression(subqueryExpression);

                        AddToPredicate(targetSelectExpression, existsPredicateExpression);

                        AddToPredicate(subqueryExpression, BuildJoinEqualityExpression(navigation, targetTableExpression, subqueryTable, querySource));

                        subqueryExpression.Predicate
                            = compositePredicateExpressionVisitor
                              .Visit(subqueryExpression.Predicate);

                        var pkPropertiesToFkPropertiesMap = navigation.ForeignKey.PrincipalKey.Properties
                                                            .Zip(navigation.ForeignKey.Properties, (k, v) => new { PkProperty = k, FkProperty = v })
                                                            .ToDictionary(x => x.PkProperty, x => x.FkProperty);

                        foreach (var ordering in selectExpression.OrderBy)
                        {
                            // ReSharper disable once PossibleNullReferenceException
                            var principalKeyProperty         = ((ordering.Expression as AliasExpression)?.Expression as ColumnExpression).Property;
                            var referencedForeignKeyProperty = pkPropertiesToFkPropertiesMap[principalKeyProperty];
                            targetSelectExpression
                            .AddToOrderBy(
                                _relationalAnnotationProvider.For(referencedForeignKeyProperty).ColumnName,
                                referencedForeignKeyProperty,
                                targetTableExpression,
                                ordering.OrderingDirection);
                        }
                    }
                    else
                    {
                        var innerJoinSelectExpression
                            = selectExpression.Clone(
                                  selectExpression.OrderBy
                                  .Select(o => o.Expression)
                                  .Last(o => o.IsAliasWithColumnExpression())
                                  .TryGetColumnExpression().TableAlias);

                        innerJoinSelectExpression.ClearProjection();

                        var innerJoinExpression = targetSelectExpression.AddInnerJoin(innerJoinSelectExpression);

                        LiftOrderBy(innerJoinSelectExpression, targetSelectExpression, innerJoinExpression);

                        innerJoinSelectExpression.IsDistinct = true;

                        innerJoinExpression.Predicate
                            = BuildJoinEqualityExpression(
                                  navigation,
                                  targetTableExpression,
                                  innerJoinExpression,
                                  querySource);
                    }

                    targetSelectExpression.Predicate
                        = compositePredicateExpressionVisitor
                          .Visit(targetSelectExpression.Predicate);

                    selectExpression = targetSelectExpression;

                    relatedEntitiesLoaders.Add(qc =>
                                               (TRelatedEntitiesLoader)_queryCompilationContext.QueryMethodProvider
                                               .CreateCollectionRelatedEntitiesLoaderMethod
                                               .Invoke(
                                                   null,
                                                   new object[]
                    {
                        qc,
                        _shaperCommandContextFactory.Create(() =>
                                                            _querySqlGeneratorFactory.CreateDefault(targetSelectExpression)),
                        queryIndex,
                        materializer.Compile()             // TODO: Used cached materializer?
                    }));
                }
            }

            return(relatedEntitiesLoaders);
        }
Пример #5
0
        protected override Expression VisitEntityQueryable(Type elementType)
        {
            var relationalQueryCompilationContext = QueryModelVisitor.QueryCompilationContext;

            var entityType = relationalQueryCompilationContext.FindEntityType(_querySource)
                             ?? _model.FindEntityType(elementType);

            var selectExpression = _selectExpressionFactory.Create(relationalQueryCompilationContext);

            QueryModelVisitor.AddQuery(_querySource, selectExpression);

            var tableName    = entityType.Relational().TableName;
            var databaseName = elementType.CustomAttributes
                               .FirstOrDefault(c => c.AttributeType == typeof(DatabaseNameAttribute))
                               ?.ConstructorArguments[0]
                               .Value
                               .ToString();

            var tableAlias
                = relationalQueryCompilationContext.CreateUniqueTableAlias(
                      _querySource.HasGeneratedItemName()
                        ? tableName[0].ToString(CultureInfo.InvariantCulture).ToUpperInvariant()
                        : (_querySource as GroupJoinClause)?.JoinClause.ItemName
                      ?? _querySource.ItemName);

            var fromSqlAnnotation
                = relationalQueryCompilationContext
                  .QueryAnnotations
                  .OfType <FromSqlResultOperator>()
                  .LastOrDefault(a => a.QuerySource == _querySource);

            Func <IQuerySqlGenerator> querySqlGeneratorFunc = selectExpression.CreateDefaultQuerySqlGenerator;

            if (fromSqlAnnotation == null)
            {
                selectExpression.AddTable(
                    new TableExpression(
                        databaseName,
                        tableName,
                        entityType.Relational().Schema,
                        tableAlias,
                        _querySource));
            }
            else
            {
                selectExpression.AddTable(
                    new FromSqlExpression(
                        fromSqlAnnotation.Sql,
                        fromSqlAnnotation.Arguments,
                        tableAlias,
                        _querySource));

                var trimmedSql = fromSqlAnnotation.Sql.TrimStart('\r', '\n', '\t', ' ');

                var useQueryComposition
                    = trimmedSql.StartsWith("SELECT ", StringComparison.OrdinalIgnoreCase) ||
                      trimmedSql.StartsWith("SELECT" + Environment.NewLine, StringComparison.OrdinalIgnoreCase) ||
                      trimmedSql.StartsWith("SELECT\t", StringComparison.OrdinalIgnoreCase);

                var requiresClientEval = !useQueryComposition;

                if (!useQueryComposition &&
                    relationalQueryCompilationContext.IsIncludeQuery)
                {
                    throw new InvalidOperationException(
                              RelationalStrings.StoredProcedureIncludeNotSupported);
                }

                if (useQueryComposition &&
                    fromSqlAnnotation.QueryModel.IsIdentityQuery() &&
                    !fromSqlAnnotation.QueryModel.ResultOperators.Any() &&
                    !relationalQueryCompilationContext.IsIncludeQuery &&
                    entityType.BaseType == null &&
                    !entityType.GetDerivedTypes().Any())
                {
                    useQueryComposition = false;
                }

                if (!useQueryComposition)
                {
                    QueryModelVisitor.RequiresClientEval = requiresClientEval;

                    querySqlGeneratorFunc = ()
                                            => selectExpression.CreateFromSqlQuerySqlGenerator(
                        fromSqlAnnotation.Sql,
                        fromSqlAnnotation.Arguments);
                }
            }

            var shaper = CreateShaper(elementType, entityType, selectExpression);

            DiscriminateProjectionQuery(entityType, selectExpression, _querySource);

            return(Expression.Call(
                       QueryModelVisitor.QueryCompilationContext.QueryMethodProvider
                       .ShapedQueryMethod
                       .MakeGenericMethod(shaper.Type),
                       EntityQueryModelVisitor.QueryContextParameter,
                       Expression.Constant(_shaperCommandContextFactory.Create(querySqlGeneratorFunc)),
                       Expression.Constant(shaper)));
        }
Пример #6
0
        private IEnumerable <Expression> CreateIncludeRelatedValuesStrategyFactories(
            IQuerySource querySource,
            IEnumerable <INavigation> navigationPath)
        {
            var selectExpression
                = _queryCompilationContext.FindSelectExpression(querySource);

            var targetTableExpression
                = selectExpression.GetTableForQuerySource(querySource);

            var canProduceInnerJoin = true;
            var navigationCount     = 0;

            foreach (var navigation in navigationPath)
            {
                var queryIndex = _queryIndexes[navigationCount];
                navigationCount++;

                var targetEntityType = navigation.GetTargetType();
                var targetTableName  = _relationalAnnotationProvider.For(targetEntityType).TableName;
                var targetTableAlias = targetTableName[0].ToString().ToLower();

                if (!navigation.IsCollection())
                {
                    var joinedTableExpression
                        = new TableExpression(
                              targetTableName,
                              _relationalAnnotationProvider.For(targetEntityType).Schema,
                              targetTableAlias,
                              querySource);

                    var valueBufferOffset = selectExpression.Projection.Count;

                    canProduceInnerJoin
                        = canProduceInnerJoin && navigation.ForeignKey.IsRequired && navigation.IsDependentToPrincipal();

                    var joinExpression
                        = canProduceInnerJoin
                            ? selectExpression
                          .AddInnerJoin(joinedTableExpression)
                            : selectExpression
                          .AddOuterJoin(joinedTableExpression);

                    var oldPredicate = selectExpression.Predicate;

                    var materializer
                        = _materializerFactory
                          .CreateMaterializer(
                              targetEntityType,
                              selectExpression,
                              (p, se) => se.AddToProjection(
                                  new AliasExpression(
                                      new ColumnExpression(
                                          _relationalAnnotationProvider.For(p).ColumnName,
                                          p,
                                          joinedTableExpression))) - valueBufferOffset,
                              querySource: null);

                    if (selectExpression.Predicate != oldPredicate)
                    {
                        var newJoinExpression = AdjustJoinExpression(selectExpression, joinExpression);

                        selectExpression.Predicate = oldPredicate;
                        selectExpression.RemoveTable(joinExpression);
                        selectExpression.AddTable(newJoinExpression);
                        joinExpression = newJoinExpression;
                    }

                    joinExpression.Predicate
                        = BuildJoinEqualityExpression(
                              navigation,
                              navigation.IsDependentToPrincipal() ? targetTableExpression : joinExpression,
                              navigation.IsDependentToPrincipal() ? joinExpression : targetTableExpression,
                              querySource);

                    targetTableExpression = joinedTableExpression;

                    yield return
                        (Expression.Lambda(
                             Expression.Call(
                                 _queryCompilationContext.QueryMethodProvider
                                 .CreateReferenceIncludeRelatedValuesStrategyMethod,
                                 Expression.Convert(
                                     EntityQueryModelVisitor.QueryContextParameter,
                                     typeof(RelationalQueryContext)),
                                 Expression.Constant(valueBufferOffset),
                                 Expression.Constant(queryIndex),
                                 materializer)));
                }
                else
                {
                    var principalTable
                        = selectExpression.Tables.Last(t => t.QuerySource == querySource);

                    foreach (var property in navigation.ForeignKey.PrincipalKey.Properties)
                    {
                        selectExpression
                        .AddToOrderBy(
                            _relationalAnnotationProvider.For(property).ColumnName,
                            property,
                            principalTable,
                            OrderingDirection.Asc);
                    }

                    var targetSelectExpression = _selectExpressionFactory.Create();

                    targetTableExpression
                        = new TableExpression(
                              targetTableName,
                              _relationalAnnotationProvider.For(targetEntityType).Schema,
                              targetTableAlias,
                              querySource);

                    targetSelectExpression.AddTable(targetTableExpression);

                    var materializer
                        = _materializerFactory
                          .CreateMaterializer(
                              targetEntityType,
                              targetSelectExpression,
                              (p, se) => se.AddToProjection(
                                  _relationalAnnotationProvider.For(p).ColumnName,
                                  p,
                                  querySource),
                              querySource: null);

                    var innerJoinSelectExpression
                        = selectExpression.Clone(
                              selectExpression.OrderBy
                              .Select(o => o.Expression)
                              .Last(o => o.IsAliasWithColumnExpression())
                              .TryGetColumnExpression().TableAlias);

                    innerJoinSelectExpression.IsDistinct = true;
                    innerJoinSelectExpression.ClearProjection();

                    var innerJoinExpression = targetSelectExpression.AddInnerJoin(innerJoinSelectExpression);

                    LiftOrderBy(innerJoinSelectExpression, targetSelectExpression, innerJoinExpression);

                    innerJoinExpression.Predicate
                        = BuildJoinEqualityExpression(
                              navigation,
                              targetTableExpression,
                              innerJoinExpression,
                              querySource);

                    selectExpression = targetSelectExpression;

                    yield return
                        (Expression.Lambda(
                             Expression.Call(
                                 _queryCompilationContext.QueryMethodProvider
                                 .CreateCollectionIncludeRelatedValuesStrategyMethod,
                                 Expression.Call(
                                     _queryCompilationContext.QueryMethodProvider.QueryMethod,
                                     EntityQueryModelVisitor.QueryContextParameter,
                                     Expression.Constant(
                                         _shaperCommandContextFactory.Create(
                                             () => _querySqlGeneratorFactory
                                             .CreateDefault(targetSelectExpression))),
                                     Expression.Constant(queryIndex, typeof(int?))),
                                 materializer)));
                }
            }
        }
Пример #7
0
        protected override Expression VisitEntityQueryable(Type elementType)
        {
            Check.NotNull(elementType, nameof(elementType));

            var relationalQueryCompilationContext = QueryModelVisitor.QueryCompilationContext;
            var entityType = _model.FindEntityType(elementType);

            var selectExpression = _selectExpressionFactory.Create(relationalQueryCompilationContext);

            QueryModelVisitor.AddQuery(_querySource, selectExpression);

            var name = _relationalAnnotationProvider.For(entityType).TableName;

            var tableAlias
                = _querySource.HasGeneratedItemName()
                    ? name[0].ToString().ToLowerInvariant()
                    : _querySource.ItemName;

            var fromSqlAnnotation
                = relationalQueryCompilationContext
                  .QueryAnnotations
                  .OfType <FromSqlResultOperator>()
                  .LastOrDefault(a => a.QuerySource == _querySource);

            Func <IQuerySqlGenerator> querySqlGeneratorFunc = selectExpression.CreateDefaultQuerySqlGenerator;

            if (fromSqlAnnotation == null)
            {
                selectExpression.AddTable(
                    new TableExpression(
                        name,
                        _relationalAnnotationProvider.For(entityType).Schema,
                        tableAlias,
                        _querySource));
            }
            else
            {
                selectExpression.AddTable(
                    new FromSqlExpression(
                        fromSqlAnnotation.Sql,
                        fromSqlAnnotation.Arguments,
                        tableAlias,
                        _querySource));

                var useQueryComposition
                    = fromSqlAnnotation.Sql
                      .TrimStart()
                      .StartsWith("SELECT ", StringComparison.OrdinalIgnoreCase);

                if (!useQueryComposition)
                {
                    if (relationalQueryCompilationContext.IsIncludeQuery)
                    {
                        throw new InvalidOperationException(
                                  RelationalStrings.StoredProcedureIncludeNotSupported);
                    }
                }

                if (useQueryComposition &&
                    fromSqlAnnotation.QueryModel.IsIdentityQuery() &&
                    !fromSqlAnnotation.QueryModel.ResultOperators.Any() &&
                    !relationalQueryCompilationContext.IsIncludeQuery)
                {
                    useQueryComposition = false;
                }

                if (!useQueryComposition)
                {
                    QueryModelVisitor.RequiresClientEval = true;

                    querySqlGeneratorFunc = ()
                                            => selectExpression.CreateFromSqlQuerySqlGenerator(
                        fromSqlAnnotation.Sql,
                        fromSqlAnnotation.Arguments);
                }
            }

            var shaper = CreateShaper(elementType, entityType, selectExpression);

            return(Expression.Call(
                       QueryModelVisitor.QueryCompilationContext.QueryMethodProvider // TODO: Don't use ShapedQuery when projecting
                       .ShapedQueryMethod
                       .MakeGenericMethod(shaper.Type),
                       EntityQueryModelVisitor.QueryContextParameter,
                       Expression.Constant(_shaperCommandContextFactory.Create(querySqlGeneratorFunc)),
                       Expression.Constant(shaper)));
        }
        protected override Expression VisitEntityQueryable(Type elementType)
        {
            if (elementType == null)
            {
                throw new ArgumentNullException(nameof(elementType));
            }

            var relationalQueryCompilationContext = QueryModelVisitor.QueryCompilationContext;


            var valueFromOpenJsonAnnotation
                = relationalQueryCompilationContext
                  .QueryAnnotations
                  .OfType <ValueFromOpenJsonOperator>()
                  .LastOrDefault(a => a.QuerySource == _querySource);

            if (valueFromOpenJsonAnnotation != null)
            {
                if (valueFromOpenJsonAnnotation.Json.NodeType == ExpressionType.MemberAccess && valueFromOpenJsonAnnotation.Json is MemberExpression me)
                {
                    var entityType = relationalQueryCompilationContext.FindEntityType(_querySource)
                                     ?? _model.FindEntityType(elementType);
                    var selectExpression = _selectExpressionFactory.Create(relationalQueryCompilationContext);
                    QueryModelVisitor.AddQuery(_querySource, selectExpression);
                    var name = entityType.Relational().TableName;
                    var tableAlias
                        = relationalQueryCompilationContext.CreateUniqueTableAlias(
                              _querySource.HasGeneratedItemName()
                                ? name[0].ToString().ToLowerInvariant()
                                : (_querySource as GroupJoinClause)?.JoinClause.ItemName
                              ?? _querySource.ItemName);
                    Func <IQuerySqlGenerator> querySqlGeneratorFunc = selectExpression.CreateDefaultQuerySqlGenerator;

                    var memberEntityType = relationalQueryCompilationContext.Model.FindEntityType(me.Expression.Type);
                    var memberProperty   = memberEntityType.FindProperty(me.Member as PropertyInfo);

                    var expr = new ValueFromOpenJsonExpression(_querySource,
                                                               valueFromOpenJsonAnnotation.Json,
                                                               valueFromOpenJsonAnnotation.Path,
                                                               tableAlias);
                    expr.PropertyMapping[expr.Json] = memberProperty;

                    //var jsonProperties = MemberAccessBindingExpressionVisitor.GetPropertyPath(expr.Json, relationalQueryCompilationContext, out var qsr);
                    //Console.WriteLine(jsonProperties);

                    //expr = (ValueFromOpenJsonExpression)Visit(expr);
                    //expr.PropertyMapping[expr.Json] = memberProperty;

                    //expr = (ValueFromOpenJsonExpression)QueryModelVisitor.ReplaceClauseReferences(expr);
                    //expr.PropertyMapping[expr.Json] = memberProperty;

                    selectExpression.AddTable(expr);

                    //var trimmedSql = valueFromOpenJsonAnnotation.Sql.TrimStart('\r', '\n', '\t', ' ');
                    var useQueryComposition = true;
                    //= trimmedSql.StartsWith("SELECT ", StringComparison.OrdinalIgnoreCase)
                    //  || trimmedSql.StartsWith("SELECT" + Environment.NewLine, StringComparison.OrdinalIgnoreCase)
                    //  || trimmedSql.StartsWith("SELECT\t", StringComparison.OrdinalIgnoreCase);
                    var requiresClientEval = !useQueryComposition;
                    if (!useQueryComposition)
                    {
                        if (relationalQueryCompilationContext.IsIncludeQuery)
                        {
                            throw new InvalidOperationException(
                                      RelationalStrings.StoredProcedureIncludeNotSupported);
                        }
                    }
                    if (useQueryComposition &&
                        valueFromOpenJsonAnnotation.QueryModel.IsIdentityQuery() &&
                        !valueFromOpenJsonAnnotation.QueryModel.ResultOperators.Any() &&
                        !relationalQueryCompilationContext.IsIncludeQuery)
                    {
                        useQueryComposition = false;
                    }

                    if (!useQueryComposition)
                    {
                        throw new NotImplementedException();
                        //QueryModelVisitor.RequiresClientEval = requiresClientEval;
                        //querySqlGeneratorFunc = ()
                        //    => selectExpression.CreateFromSqlQuerySqlGenerator(
                        //        fromSqlAnnotation.Sql,
                        //        fromSqlAnnotation.Arguments);
                    }

                    var shaper = CreateShaper(elementType, entityType, selectExpression);

                    return(Expression.Call(
                               QueryModelVisitor.QueryCompilationContext.QueryMethodProvider // TODO: Don't use ShapedQuery when projecting
                               .ShapedQueryMethod
                               .MakeGenericMethod(shaper.Type),
                               EntityQueryModelVisitor.QueryContextParameter,
                               Expression.Constant(_shaperCommandContextFactory.Create(querySqlGeneratorFunc)),
                               Expression.Constant(shaper)));

                    //var member = valueFromOpenJsonAnnotation.Arguments as MemberExpression;
                    //if (member.Type == typeof(string))
                    //{



                    //    var m = this.VisitMember(member);
                    //}
                }
            }

            return(base.VisitEntityQueryable(elementType));
        }
Пример #9
0
        protected override Expression VisitEntityQueryable(Type elementType)
        {
            Check.NotNull(elementType, nameof(elementType));

            var queryMethodInfo = CreateValueBufferMethodInfo;
            var relationalQueryCompilationContext = QueryModelVisitor.QueryCompilationContext;
            var entityType       = _model.FindEntityType(elementType);
            var selectExpression = _selectExpressionFactory.Create();
            var name             = _relationalAnnotationProvider.For(entityType).TableName;

            var tableAlias
                = _querySource.HasGeneratedItemName()
                    ? name[0].ToString().ToLowerInvariant()
                    : _querySource.ItemName;

            var fromSqlAnnotation
                = relationalQueryCompilationContext
                  .GetCustomQueryAnnotations(RelationalQueryableExtensions.FromSqlMethodInfo)
                  .LastOrDefault(a => a.QuerySource == _querySource);

            var composable = true;
            var sqlString  = "";

            object[] sqlParameters = null;

            if (fromSqlAnnotation == null)
            {
                selectExpression.AddTable(
                    new TableExpression(
                        name,
                        _relationalAnnotationProvider.For(entityType).Schema,
                        tableAlias,
                        _querySource));
            }
            else
            {
                sqlString     = (string)fromSqlAnnotation.Arguments[1];
                sqlParameters = (object[])fromSqlAnnotation.Arguments[2];

                selectExpression.AddTable(
                    new RawSqlDerivedTableExpression(
                        sqlString,
                        sqlParameters,
                        tableAlias,
                        _querySource));

                var sqlStart = sqlString.SkipWhile(char.IsWhiteSpace).Take(7).ToArray();

                if (sqlStart.Length != 7 ||
                    !char.IsWhiteSpace(sqlStart.Last()) ||
                    !new string(sqlStart).StartsWith("SELECT", StringComparison.OrdinalIgnoreCase))
                {
                    if (relationalQueryCompilationContext.QueryAnnotations
                        .OfType <IncludeQueryAnnotation>().Any())
                    {
                        throw new InvalidOperationException(RelationalStrings.StoredProcedureIncludeNotSupported);
                    }

                    QueryModelVisitor.RequiresClientEval = true;

                    composable = false;
                }

                if (fromSqlAnnotation.QueryModel.IsIdentityQuery() &&
                    !fromSqlAnnotation.QueryModel.ResultOperators.Any())
                {
                    composable = false;
                }
            }

            QueryModelVisitor.AddQuery(_querySource, selectExpression);

            var queryMethodArguments
                = new List <Expression>
                {
                Expression.Constant(_querySource),
                _valueBufferParameter,
                Expression.Constant(0)
                };

            if (QueryModelVisitor.QueryCompilationContext
                .QuerySourceRequiresMaterialization(_querySource) ||
                QueryModelVisitor.RequiresClientEval)
            {
                var materializer
                    = _materializerFactory
                      .CreateMaterializer(
                          entityType,
                          selectExpression,
                          (p, se) =>
                          se.AddToProjection(
                              _relationalAnnotationProvider.For(p).ColumnName,
                              p,
                              _querySource),
                          _querySource);

                queryMethodInfo
                    = CreateEntityMethodInfo.MakeGenericMethod(elementType);

                queryMethodArguments.AddRange(
                    new[]
                {
                    EntityQueryModelVisitor.QueryContextParameter,
                    Expression.Constant(entityType),
                    Expression.Constant(QueryModelVisitor.QueryCompilationContext.IsTrackingQuery),
                    Expression.Constant(_keyValueFactorySource.GetKeyFactory(entityType.FindPrimaryKey())),
                    materializer,
                    Expression.Constant(false),
                    Expression.Constant(QueryModelVisitor.QueryCompilationContext.IsQueryBufferRequired)
                });
            }

            Func <ISqlQueryGenerator> sqlQueryGeneratorFunc;

            if (composable)
            {
                sqlQueryGeneratorFunc = selectExpression.CreateGenerator;
            }
            else
            {
                sqlQueryGeneratorFunc = () =>
                                        selectExpression.CreateRawCommandGenerator(
                    sqlString,
                    sqlParameters);
            }

            return(Expression.Call(
                       QueryModelVisitor.QueryCompilationContext.QueryMethodProvider // TODO: Don't use ShapedQuery when projecting
                       .ShapedQueryMethod
                       .MakeGenericMethod(queryMethodInfo.ReturnType),
                       EntityQueryModelVisitor.QueryContextParameter,
                       Expression.Constant(_commandBuilderFactory.Create(sqlQueryGeneratorFunc)),
                       Expression.Lambda(
                           Expression.Call(queryMethodInfo, queryMethodArguments),
                           _valueBufferParameter)));
        }