/// <summary>
        /// Resolve read only expression
        /// </summary>
        /// <param name="elementType"></param>
        /// <returns></returns>
        protected override Expression VisitEntityQueryable([NotNull] Type elementType)
        {
            Check.NotNull(elementType, nameof(elementType));

            // create then add read only expression
            var cypherQueryCompilationContext = QueryModelVisitor
                                                .QueryCompilationContext;

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

            var readOnlyExpression = _readOnlyExpressionFactory
                                     .Create(cypherQueryCompilationContext);

            QueryModelVisitor.AddQuery(
                _querySource,
                readOnlyExpression
                );


            // unique node alias either from the Relinq query source if not generated or the first label
            string[] labels = entityType.Cypher().Labels;
            string   alias  = cypherQueryCompilationContext
                              .CreateUniqueNodeAlias(
                _querySource.HasGeneratedItemName()
                        ? labels[0][0].ToString().ToLowerInvariant()
                        : _querySource.ItemName
                );

            // TODO: Use from SQL annotation?
            // default match
            readOnlyExpression.AddReadingClause(
                new MatchExpression(
                    new PatternExpression(
                        new NodePatternExpression(
                            labels,
                            _querySource,
                            alias
                            )
                        )
                    )
                );

            // bundle the sql (cypher) generator inside the shaper command factory
            Func <IQuerySqlGenerator> querySqlGeneratorFunc = readOnlyExpression
                                                              .CreateDefaultQueryCypherGenerator;
            var shaper = CreateShaper(elementType, entityType, readOnlyExpression);

            return(Expression.Call(
                       QueryModelVisitor.QueryCompilationContext.QueryMethodProvider
                       .ShapedQueryMethod
                       .MakeGenericMethod(shaper.Type),
                       EntityQueryModelVisitor.QueryContextParameter,
                       Expression.Constant(_shaperCommandContextFactory.Create(querySqlGeneratorFunc)),
                       Expression.Constant(shaper)));
        }
示例#2
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)));
        }
示例#3
0
        protected override Expression VisitEntityQueryable(Type elementType)
        {
            Check.NotNull(elementType, nameof(elementType));

            var queryMethodInfo = CreateValueBufferMethodInfo;
            var relationalQueryCompilationContext = QueryModelVisitor.QueryCompilationContext;
            var entityType       = relationalQueryCompilationContext.Model.GetEntityType(elementType);
            var selectExpression = new SelectExpression();
            var name             = relationalQueryCompilationContext.RelationalExtensions.For(entityType).TableName;

            var tableAlias
                = _querySource.HasGeneratedItemName()
                    ? name[0].ToString().ToLower()
                    : _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,
                        relationalQueryCompilationContext.RelationalExtensions.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(Strings.StoredProcedureIncludeNotSupported);
                    }

                    QueryModelVisitor.RequiresClientEval = true;

                    composable = false;
                }

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

            QueryModelVisitor.AddQuery(_querySource, selectExpression);

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

            if (QueryModelVisitor.QueryCompilationContext
                .QuerySourceRequiresMaterialization(_querySource) ||
                QueryModelVisitor.RequiresClientEval)
            {
                var materializer
                    = new MaterializerFactory(
                          relationalQueryCompilationContext
                          .EntityMaterializerSource)
                      .CreateMaterializer(
                          entityType,
                          selectExpression,
                          (p, se) =>
                          se.AddToProjection(
                              relationalQueryCompilationContext.RelationalExtensions.For(p).ColumnName,
                              p,
                              _querySource),
                          QueryModelVisitor.QueryCompilationContext.RelationalExtensions,
                          _querySource);

                queryMethodInfo
                    = CreateEntityMethodInfo.MakeGenericMethod(elementType);

                var keyFactory
                    = relationalQueryCompilationContext.EntityKeyFactorySource
                      .GetKeyFactory(entityType.GetPrimaryKey());

                queryMethodArguments.AddRange(
                    new[]
                {
                    Expression.Constant(entityType),
                    Expression.Constant(QueryModelVisitor.QuerySourceRequiresTracking(_querySource)),
                    Expression.Constant(keyFactory),
                    Expression.Constant(entityType.GetPrimaryKey().Properties),
                    materializer
                });
            }

            Func <ISqlQueryGenerator> sqlQueryGeneratorFactory;

            if (composable)
            {
                sqlQueryGeneratorFactory = () =>
                                           relationalQueryCompilationContext.CreateSqlQueryGenerator(selectExpression);
            }
            else
            {
                sqlQueryGeneratorFactory = () =>
                                           new RawSqlQueryGenerator(selectExpression, sqlString, sqlParameters, relationalQueryCompilationContext.TypeMapper);
            }

            return(Expression.Call(
                       relationalQueryCompilationContext.QueryMethodProvider.ShapedQueryMethod
                       .MakeGenericMethod(queryMethodInfo.ReturnType),
                       EntityQueryModelVisitor.QueryContextParameter,
                       Expression.Constant(
                           new CommandBuilder(
                               sqlQueryGeneratorFactory,
                               relationalQueryCompilationContext.ValueBufferFactoryFactory)),
                       Expression.Lambda(
                           Expression.Call(queryMethodInfo, queryMethodArguments),
                           _valueBufferParameter)));
        }
示例#4
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));
        }