コード例 #1
0
        private static void ConjoinAsAndOperation(ICriterion rightCriterion, BinaryFilterResult toReturn, AggregateNodeStatus agg, FilterResult left, ICriterion leftCriterion, FilterResult right, Join[] allJoins, QueryOver <AggregateNodeStatus, AggregateNodeStatus> newQuery)
        {
            // If either side is a binary, it'll already have a subquery generated, so can use that,
            // otherwise we need to make one
            var leftAsBinary     = left as BinaryFilterResult;
            var rightAsBinary    = right as BinaryFilterResult;
            var leftAsSchema     = left as SchemaFilterResult;
            var rightAsSchema    = right as SchemaFilterResult;
            var addedLeftSchema  = false;
            var addedRightSchema = false;

            if (leftAsSchema != null && rightAsSchema != null)
            {
                toReturn.Joins = allJoins;
                var addSchemaJoin = Restrictions.Conjunction()
                                    .Add(leftAsSchema.NhCriterion)
                                    .Add(rightAsSchema.NhCriterion);
                toReturn.Subquery = newQuery.Where(addSchemaJoin);
            }
            else if (leftAsSchema != null)
            {
                toReturn.Joins = allJoins;

                var theQuery = QueryOver.Of(() => agg);
                if (rightCriterion != null)
                {
                    theQuery = theQuery.Where(rightCriterion);
                }
                foreach (var rightJoin in allJoins)
                {
                    theQuery = theQuery.JoinAlias(rightJoin.Path, rightJoin.Alias, rightJoin.JoinType);
                }

                // One side is a schema restriction, and we can generate faster sql by avoiding
                // a subquery and just adding the schema restriction to the field restriction(s)
                var addSchemaJoin = Restrictions.Conjunction()
                                    .Add(leftAsSchema.NhCriterion)
                                    .Add(GetAutoSubqueryCriterion(right));

                theQuery          = theQuery.Where(addSchemaJoin);
                toReturn.Subquery = theQuery;
                return;

                addedLeftSchema = true;
            }
            else if (rightAsSchema != null)
            {
                toReturn.Joins = allJoins;

                var theQuery = QueryOver.Of(() => agg);
                if (leftCriterion != null)
                {
                    theQuery = theQuery.Where(rightCriterion);
                }
                foreach (var rightJoin in allJoins)
                {
                    theQuery = theQuery.JoinAlias(rightJoin.Path, rightJoin.Alias, rightJoin.JoinType);
                }

                // One side is a schema restriction, and we can generate faster sql by avoiding
                // a subquery and just adding the schema restriction to the field restriction(s)
                var addSchemaJoin = Restrictions.Conjunction()
                                    .Add(GetAutoSubqueryCriterion(left))
                                    .Add(rightAsSchema.NhCriterion);

                theQuery          = theQuery.Where(addSchemaJoin);
                toReturn.Subquery = theQuery;
                return;

                addedRightSchema = true;
            }

            if (leftAsBinary == null && !addedLeftSchema)
            {
                left.Subquery = QueryOver.Of(() => agg);

                if (leftCriterion != null)
                {
                    left.Subquery = left.Subquery.Where(leftCriterion);
                }
                foreach (var leftJoin in left.Joins)
                {
                    left.Subquery = left.Subquery.JoinAlias(leftJoin.Path, leftJoin.Alias, leftJoin.JoinType);
                }
            }

            if (rightAsBinary == null && !addedRightSchema)
            {
                right.Subquery = QueryOver.Of(() => agg);
                if (rightCriterion != null)
                {
                    right.Subquery = right.Subquery.Where(rightCriterion);
                }
                foreach (var rightJoin in right.Joins)
                {
                    right.Subquery = right.Subquery.JoinAlias(rightJoin.Path, rightJoin.Alias, rightJoin.JoinType);
                }
            }

            toReturn.Joins    = new List <Join>(left.Joins);
            toReturn.Subquery = left
                                .Subquery
                                .WithSubquery.WhereProperty(x => x.NodeVersion.Id).In(right.Subquery.Select(x => x.NodeVersion.Id));
        }
コード例 #2
0
        public override FilterResult VisitBinary(BinaryExpression node)
        {
            var left  = Visit(node.Left);
            var right = Visit(node.Right);

            if (left == null && right != null)
            {
                return(right);
            }
            if (left != null && right == null)
            {
                return(left);
            }

            AggregateNodeStatus agg = null;

            // Combine a distinct set of all the joins in the left and right sides, we might use this later
            var allJoins = left.Joins.Concat(right.Joins)
                           .DistinctBy(x => x.Path.ToString() + x.Alias.ToString() + x.JoinType.ToString()).ToArray();

            var newQuery = QueryOver.Of <AggregateNodeStatus>(() => agg);

            foreach (var allJoin in allJoins)
            {
                newQuery = newQuery.JoinAlias(allJoin.Path, allJoin.Alias, allJoin.JoinType);
            }

            // If we're returning a binary result, we need to let the upper branch in the tree know if this is
            // and And or an Or binary. If it's an And binary, then we're going to have subqueries, because in the EVM
            // datamodel you can't do "and" expressions on the same join because different values occupy different rows.
            // If we have subqueries, we need to be aware of that when combining the "outer" binary bearing in mind there
            // may be several compound binaries in the expression tree and thus this method might be recursively walking
            // the tree (depth-first of course)

            var isConjunction = false;

            switch (node.NodeType)
            {
            case ExpressionType.And:
            case ExpressionType.AndAlso:
                isConjunction = true;
                break;

            case ExpressionType.Or:
            case ExpressionType.OrElse:
                break;

            default:
                throw new InvalidOperationException("This provider only supports binary expressions with And, AndAlso, Or, OrElse expression types. ExpressionType was {0}".InvariantFormat(node.NodeType.ToString()));
            }

            var toReturn       = new BinaryFilterResult(isConjunction);
            var leftCriterion  = GetCriterion(left);
            var rightCriterion = GetCriterion(right);

            if (toReturn.IsAndOperation)
            {
                // To do an "and", we'll construct the left and right queries, and the output
                // query will be "where left also has a subquery matching right"
                ConjoinAsAndOperation(rightCriterion, toReturn, agg, left, leftCriterion, right, allJoins, newQuery);
            }
            else
            {
                // To do an "or", we can combine the queries into one, provided either side isn't a Binary that is an "and"
                // in which case we need to add it as a subquery as its simple criterion won't have enough info
                bool leftIsSubquery  = false;
                bool rightIsSubquery = false;

                var leftAsBinary  = left as BinaryFilterResult;
                var rightAsBinary = right as BinaryFilterResult;
                if (leftAsBinary != null && leftAsBinary.IsAndOperation)
                {
                    leftIsSubquery = true;
                }
                if (rightAsBinary != null && rightAsBinary.IsAndOperation)
                {
                    rightIsSubquery = true;
                }

                if (leftIsSubquery && rightIsSubquery)
                {
                    ConjoinAsAndOperation(rightCriterion, toReturn, agg, left, leftCriterion, right, allJoins, newQuery);
                }
                else if (rightIsSubquery)
                {
                    toReturn.Subquery = newQuery;
                    var rightSubquery = Subqueries.WhereProperty <AggregateNodeStatus>(x => x.NodeVersion.Id).In(right.Subquery.Select(x => x.NodeVersion.Id));
                    if (leftCriterion != null)
                    {
                        var disjunction = Restrictions.Disjunction().Add(leftCriterion).Add(rightSubquery);
                        toReturn.Subquery = toReturn.Subquery.Where(disjunction);
                        toReturn.Joins    = left.Joins;
                    }
                    else
                    {
                        toReturn.Subquery = toReturn.Subquery.Where(rightSubquery);
                    }
                }
                else if (leftIsSubquery)
                {
                    toReturn.Subquery = newQuery;

                    var leftSubquery = Subqueries.WhereProperty <AggregateNodeStatus>(x => x.NodeVersion.Id).In(left.Subquery.Select(x => x.NodeVersion.Id));
                    if (rightCriterion != null)
                    {
                        var disjunction = Restrictions.Disjunction().Add(rightCriterion).Add(leftSubquery);
                        toReturn.Subquery = toReturn.Subquery.Where(disjunction);
                        toReturn.Joins    = right.Joins;
                    }
                    else
                    {
                        toReturn.Subquery = toReturn.Subquery.Where(leftSubquery);
                    }
                }
                else
                {
                    var orBoth = Restrictions.Disjunction()
                                 .Add(leftCriterion)
                                 .Add(rightCriterion);
                    newQuery             = newQuery.Where(orBoth);
                    toReturn.NhCriterion = orBoth;

                    toReturn.Joins    = new List <Join>(allJoins);
                    toReturn.Subquery = newQuery;
                }
            }
            return(toReturn);
        }