Пример #1
0
        private static void GetIncludeExcludes <T>(IList <Expression> expressions, IncludeExcludeParser parser, FetchNode rootNode, bool isInclude /* as opposed to exclude */)
            where T : class, new()
        {
            if (expressions == null)
            {
                return;
            }

            foreach (var expression in expressions)
            {
                parser.ParseExpression <T>(expression, rootNode, isInclude);
            }
        }
Пример #2
0
        private static void GetIncludeExcludes <T>(
            IList <Expression> expressions,
            ref IDictionary <Type, IList <IColumn> > includes,
            IncludeExcludeParser parser) where T : class, new()
        {
            if (expressions != null)
            {
                includes = new Dictionary <Type, IList <IColumn> >();
                foreach (var expression in expressions)
                {
                    var column = parser.ParseExpression(expression);
                    if (!includes.ContainsKey(column.Map.Type))
                    {
                        includes.Add(column.Map.Type, new List <IColumn>());
                    }

                    includes[column.Map.Type].Add(column);
                }
            }
        }
Пример #3
0
        public SelectWriterResult GenerateSql <T>(SelectQuery <T> selectQuery, bool enforceAlias = false)
            where T : class, new()
        {
            // TODO: one StringBuilder to rule them all - Good luck with that ;-) (insertions are expensive)
            var sql = new StringBuilder();
            DynamicParameters parameters = new DynamicParameters();

            // get fetch tree structure
            int aliasCounter;
            int numberCollectionFetches;
            var rootNode = this.fetchTreeParser.GetFetchTree(selectQuery, out aliasCounter, out numberCollectionFetches);

            IDictionary <Type, IList <IColumn> > includes = null;
            IDictionary <Type, IList <IColumn> > excludes = null;

            if ((selectQuery.Includes != null && selectQuery.Includes.Any()) || (selectQuery.Excludes != null && selectQuery.Excludes.Any()))
            {
                var parser = new IncludeExcludeParser(this.Configuration);
                GetIncludeExcludes <T>(selectQuery.Includes, ref includes, parser);
                GetIncludeExcludes <T>(selectQuery.Excludes, ref excludes, parser);
            }

            if (numberCollectionFetches > 0)
            {
                if (numberCollectionFetches > 1 && (rootNode.Children.Count(c => c.Value.Column.Relationship == RelationshipType.OneToMany || c.Value.ContainedCollectionfetchesCount > 0) > 1))
                {
                    // multiple one to many branches so we'll perform a union query
                    if (selectQuery.TakeN > 0 || selectQuery.SkipN > 0)
                    {
                        // TODO this is temporary, should generate union query similar to next
                        rootNode = this.GeneratePagingCollectionSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, includes, excludes, ref parameters);
                    }
                    else
                    {
                        rootNode = this.GenerateNoPagingUnionSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, includes, excludes, ref parameters);
                    }
                }
                else
                {
                    if (selectQuery.TakeN > 0 || selectQuery.SkipN > 0)
                    {
                        // we're sub-selecting so need to use a subquery
                        rootNode = this.GeneratePagingCollectionSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, includes, excludes, ref parameters);
                    }
                    else
                    {
                        // we're fetching all things
                        rootNode = this.GenerateNoPagingSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, includes, excludes, ref parameters);
                    }
                }
            }
            else
            {
                // no collection fetches
                rootNode = this.GenerateNoPagingSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, includes, excludes, ref parameters);
            }

            return(new SelectWriterResult(sql.ToString(), parameters, rootNode)
            {
                NumberCollectionsFetched = numberCollectionFetches
            });
        }
Пример #4
0
        private SelectWriterResult InnerGenerateSql <T>(SelectQuery <T> selectQuery, AutoNamingDynamicParameters parameters, bool enforceAlias, FetchNode rootNode, int numberCollectionFetches, StringBuilder sql, bool isProjectedQuery)
            where T : class, new()   // add in any includes or excludes
        {
            if ((selectQuery.Includes != null && selectQuery.Includes.Any()) || (selectQuery.Excludes != null && selectQuery.Excludes.Any()))
            {
                var parser = new IncludeExcludeParser(this.Configuration);
                rootNode = rootNode ?? new FetchNode();
                GetIncludeExcludes <T>(selectQuery.Includes, parser, rootNode, true);
                GetIncludeExcludes <T>(selectQuery.Excludes, parser, rootNode, false);
            }

            if (numberCollectionFetches > 0)
            {
                if (numberCollectionFetches > 1 && (rootNode.Children.Count(c => c.Value.Column.Relationship == RelationshipType.OneToMany || c.Value.ContainedCollectionfetchesCount > 0) > 1))
                {
                    // multiple one to many branches so we'll perform a union query
                    if (selectQuery.TakeN > 0 || selectQuery.SkipN > 0)
                    {
                        // TODO this is temporary, should generate union query similar to next
                        rootNode = this.GeneratePagingCollectionSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, parameters, isProjectedQuery);
                    }
                    else
                    {
                        rootNode = this.GenerateNoPagingUnionSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, parameters, isProjectedQuery);
                    }
                }
                else
                {
                    if (selectQuery.TakeN > 0 || selectQuery.SkipN > 0)
                    {
                        // we're sub-selecting so need to use a subquery
                        rootNode = this.GeneratePagingCollectionSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, parameters, isProjectedQuery);
                    }
                    else
                    {
                        // we're fetching all things
                        rootNode = this.GenerateNoPagingSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, parameters, isProjectedQuery);
                    }
                }
            }
            else
            {
                // no collection fetches
                // see if we can transform to union query for non-root disjunctions
                var nonRootDisjunctionTransformationSucceeded = false;
                if (selectQuery.TakeN == 0 && selectQuery.SkipN == 0)
                {
                    var outerJoinDisjunctionTransformer = new OuterJoinDisjunctionTransformer(this.Configuration);
                    int substitutedWhereClauseIndex     = -1;
                    Expression <Func <T, bool> > substitutedWhereClause       = null;
                    IEnumerable <Expression <Func <T, bool> > > substitutions = null;
                    foreach (var whereClauseEntry in selectQuery.WhereClauses.AsSmartEnumerable())
                    {
                        var whereClause = whereClauseEntry.Value;
                        var result      = outerJoinDisjunctionTransformer.AttemptGetOuterJoinDisjunctions(whereClause);
                        if (result.ContainsOuterJoinDisjunction)
                        {
                            if (substitutedWhereClause != null)
                            {
                                // we'll bail out here as we're not supporting multiple disjunctions
                                substitutedWhereClause = null;
                                break;
                            }

                            substitutedWhereClauseIndex = whereClauseEntry.Index;
                            substitutedWhereClause      = whereClause;
                            substitutions = result.UnionWhereClauses;
                        }
                    }

                    if (substitutedWhereClause != null)
                    {
                        // we don't want to order the unioned queries, we'll order them subsequently
                        var originalOrderClauses = selectQuery.OrderClauses;
                        selectQuery.OrderClauses = new Queue <OrderClause <T> >();

                        // we need to copy the fetch node and re-use it inside every query
                        var originalRootNode = rootNode != null
                                                   ? rootNode.Clone()
                                                   : new FetchNode(); // we force the unions to have the same alias

                        foreach (var substitution in substitutions.AsSmartEnumerable())
                        {
                            // swap out the original where clause for the substitute
                            selectQuery.WhereClauses.RemoveAt(substitutedWhereClauseIndex);
                            selectQuery.WhereClauses.Insert(substitutedWhereClauseIndex, substitution.Value);
                            var substitutionRootNode = originalRootNode.Clone();
                            rootNode = this.GenerateNoPagingSql(selectQuery, enforceAlias, substitutionRootNode, sql, numberCollectionFetches, parameters, isProjectedQuery);
                            if (!substitution.IsLast)
                            {
                                sql.Append(" union ");
                            }
                        }

                        if (originalOrderClauses != null && originalOrderClauses.Any())
                        {
                            this.AddOrderByClause(originalOrderClauses, sql, rootNode);
                        }

                        nonRootDisjunctionTransformationSucceeded = true;
                    }
                }

                if (!nonRootDisjunctionTransformationSucceeded)
                {
                    rootNode = this.GenerateNoPagingSql(selectQuery, enforceAlias, rootNode, sql, numberCollectionFetches, parameters, isProjectedQuery);
                }
            }

            return(new SelectWriterResult(sql.ToString(), parameters, rootNode)
            {
                NumberCollectionsFetched = numberCollectionFetches
            });
        }