private void ProcessFlattenedJoin(GroupJoinClause nonAggregatingJoin, QuerySourceUsageLocator locator) { var nhJoin = locator.LeftJoin ? new NhOuterJoinClause(nonAggregatingJoin.JoinClause) : (IQuerySource)nonAggregatingJoin.JoinClause; // Need to: // 1. Remove the group join and replace it with a join // 2. Remove the corresponding "from" clause (the thing that was doing the flattening) // 3. Rewrite the query model to reference the "join" rather than the "from" clause SwapClause(nonAggregatingJoin, (IBodyClause)nhJoin); _model.BodyClauses.Remove((IBodyClause)locator.Usages[0]); SwapQuerySourceVisitor querySourceSwapper; if (locator.LeftJoin) { // As we wrapped the join clause we have to update all references to the wrapped clause querySourceSwapper = new SwapQuerySourceVisitor(nonAggregatingJoin.JoinClause, nhJoin); _model.TransformExpressions(querySourceSwapper.Swap); } querySourceSwapper = new SwapQuerySourceVisitor(locator.Usages[0], nhJoin); _model.TransformExpressions(querySourceSwapper.Swap); }
private void ProcessFlattenedJoin(GroupJoinClause nonAggregatingJoin) { // Need to: // 1. Remove the group join and replace it with a join // 2. Remove the corresponding "from" clause (the thing that was doing the flattening) // 3. Rewrite the selector to reference the "join" rather than the "from" clause SwapClause(nonAggregatingJoin, nonAggregatingJoin.JoinClause); // TODO - don't like use of _locator here; would rather we got this passed in. Ditto on next line (esp. the cast) _model.BodyClauses.Remove(_locator.Clauses[0]); var querySourceSwapper = new SwapQuerySourceVisitor((IQuerySource)_locator.Clauses[0], nonAggregatingJoin.JoinClause); _model.SelectClause.TransformExpressions(querySourceSwapper.Swap); }
protected override Expression VisitSubQueryExpression(SubQueryExpression expression) { // If the sub query's main (and only) from clause is one of our aggregating group bys, then swap it GroupJoinClause groupJoin = LocateGroupJoinQuerySource(expression.QueryModel); if (groupJoin != null) { Expression innerSelector = new SwapQuerySourceVisitor(groupJoin.JoinClause, expression.QueryModel.MainFromClause). Swap(groupJoin.JoinClause.InnerKeySelector); expression.QueryModel.MainFromClause.FromExpression = groupJoin.JoinClause.InnerSequence; // TODO - this only works if the key selectors are not composite. Needs improvement... expression.QueryModel.BodyClauses.Add(new WhereClause(Expression.Equal(innerSelector, groupJoin.JoinClause.OuterKeySelector))); } return expression; }
private static void FlattenSubQuery(SubQueryExpression subQueryExpression, QueryModel queryModel) { // we can not flattern subquery if outer query has body clauses. var subQueryModel = subQueryExpression.QueryModel; var subQueryMainFromClause = subQueryModel.MainFromClause; if (queryModel.BodyClauses.Count == 0) { foreach (var resultOperator in subQueryModel.ResultOperators) queryModel.ResultOperators.Add(resultOperator); foreach (var bodyClause in subQueryModel.BodyClauses) queryModel.BodyClauses.Add(bodyClause); } else { var cro = new ContainsResultOperator(new QuerySourceReferenceExpression(subQueryMainFromClause)); var newSubQueryModel = subQueryModel.Clone(); newSubQueryModel.ResultOperators.Add(cro); newSubQueryModel.ResultTypeOverride = typeof (bool); var where = new WhereClause(new SubQueryExpression(newSubQueryModel)); queryModel.BodyClauses.Add(where); if (!queryModel.BodyClauses.OfType<OrderByClause>().Any()) { var orderByClauses = subQueryModel.BodyClauses.OfType<OrderByClause>(); foreach (var orderByClause in orderByClauses) queryModel.BodyClauses.Add(orderByClause); } } var visitor1 = new PagingRewriterSelectClauseVisitor(); queryModel.SelectClause.TransformExpressions(visitor1.Swap); // Point all query source references to the outer from clause var visitor2 = new SwapQuerySourceVisitor(queryModel.MainFromClause, subQueryMainFromClause); queryModel.TransformExpressions(visitor2.Swap); // Replace the outer query source queryModel.MainFromClause = subQueryMainFromClause; }
private static void FlattenSubQuery(QueryModel queryModel, QueryModel subQueryModel) { // Move the result operator up if (queryModel.ResultOperators.Count > 0 && queryModel.ResultOperators.Any(resultOperator => !_resultOperators.Contains(resultOperator.GetType()))) { throw new NotImplementedException(); } var groupBy = (GroupResultOperator)subQueryModel.ResultOperators[0]; queryModel.ResultOperators.Insert(0, groupBy); for (var i = 0; i < queryModel.BodyClauses.Count; i++) { var clause = queryModel.BodyClauses[i]; clause.TransformExpressions(s => GroupBySelectClauseRewriter.ReWrite(s, groupBy, subQueryModel)); //all outer where clauses actually are having clauses var whereClause = clause as WhereClause; if (whereClause != null) { queryModel.BodyClauses.RemoveAt(i); queryModel.BodyClauses.Insert(i, new NhHavingClause(whereClause.Predicate)); } } foreach (var bodyClause in subQueryModel.BodyClauses) queryModel.BodyClauses.Add(bodyClause); // Replace the outer select clause... queryModel.SelectClause.TransformExpressions(s => GroupBySelectClauseRewriter.ReWrite(s, groupBy, subQueryModel)); // Point all query source references to the outer from clause var visitor = new SwapQuerySourceVisitor(queryModel.MainFromClause, subQueryModel.MainFromClause); queryModel.TransformExpressions(visitor.Swap); // Replace the outer query source queryModel.MainFromClause = subQueryModel.MainFromClause; }
private static void FlattenSubQuery(QueryModel queryModel, QueryModel subQueryModel, GroupResultOperator groupBy) { foreach (var resultOperator in queryModel.ResultOperators.Where(resultOperator => !AcceptableOuterResultOperators.Contains(resultOperator.GetType()))) { throw new NotImplementedException("Cannot use group by with the " + resultOperator.GetType().Name + " result operator."); } // Move the result operator up. SubQueryFromClauseFlattener.InsertResultOperators(subQueryModel.ResultOperators, queryModel); for (var i = 0; i < queryModel.BodyClauses.Count; i++) { var clause = queryModel.BodyClauses[i]; clause.TransformExpressions(s => GroupBySelectClauseRewriter.ReWrite(s, groupBy, subQueryModel)); //all outer where clauses actually are having clauses var whereClause = clause as WhereClause; if (whereClause != null) { queryModel.BodyClauses.RemoveAt(i); queryModel.BodyClauses.Insert(i, new NhHavingClause(whereClause.Predicate)); } } foreach (var bodyClause in subQueryModel.BodyClauses) queryModel.BodyClauses.Add(bodyClause); // Replace the outer select clause... queryModel.SelectClause.TransformExpressions(s => GroupBySelectClauseRewriter.ReWrite(s, groupBy, subQueryModel)); // Point all query source references to the outer from clause var visitor = new SwapQuerySourceVisitor(queryModel.MainFromClause, subQueryModel.MainFromClause); queryModel.TransformExpressions(visitor.Swap); // Replace the outer query source queryModel.MainFromClause = subQueryModel.MainFromClause; }
private static Expression ProcessSubquery(ISessionFactory sessionFactory, ICollection<ExpressionHolder> elementExpression, QueryModel queryModel, Expression @group, QueryModel subQueryModel) { var subQueryMainFromClause = subQueryModel.MainFromClause; var restrictions = subQueryModel.BodyClauses .OfType<WhereClause>() .Select(w => new NhWithClause(w.Predicate)); var join = new NhJoinClause(subQueryMainFromClause.ItemName, subQueryMainFromClause.ItemType, subQueryMainFromClause.FromExpression, restrictions); queryModel.BodyClauses.Add(@join); var visitor = new SwapQuerySourceVisitor(subQueryMainFromClause, @join); queryModel.TransformExpressions(visitor.Swap); var selector = subQueryModel.SelectClause.Selector; var collectionType = subQueryModel.GetResultType(); var elementType = selector.Type; var source = new QuerySourceReferenceExpression(@join); return BuildSubCollectionQuery(sessionFactory, elementExpression, @group, source, selector, elementType, collectionType); }
public static void ReWrite(QueryModel queryModel, ISessionFactory sessionFactory) { var nsqmv = new NestedSelectDetector(); nsqmv.VisitExpression(queryModel.SelectClause.Selector); if (!nsqmv.HasSubquery) return; var subQueryModel = nsqmv.Expression.QueryModel; var mainFromClause = subQueryModel.MainFromClause; var restrictions = subQueryModel.BodyClauses .OfType<WhereClause>() .Select(w => new NhWithClause(w.Predicate)); var join = new NhJoinClause(mainFromClause.ItemName, mainFromClause.ItemType, mainFromClause.FromExpression, restrictions); queryModel.BodyClauses.Add(join); var visitor = new SwapQuerySourceVisitor(subQueryModel.MainFromClause, join); queryModel.TransformExpressions(visitor.Swap); var ctor = Tuple.Type.GetConstructor(System.Type.EmptyTypes); var key = Expression.Parameter(Tuple.Type, "key"); var values = Expression.Parameter(typeof (IEnumerable<Tuple>), "values"); var expressions = new List<ExpressionHolder>(); var rewriter = new SelectClauseRewriter(key, values, expressions); var resultSelector = rewriter.VisitExpression(queryModel.SelectClause.Selector); var field = Tuple.Type.GetField("Items"); var keySelector = CreateSelector(ctor, field, expressions, 0); var elementSelector = CreateSelector(ctor, field, expressions, 1); var cast = EnumerableHelper.GetMethod("Cast", new[] {typeof (IEnumerable)}, new[] {typeof (object[])}); var groupBy = EnumerableHelper.GetMethod("GroupBy", new[] {typeof (IEnumerable<>), typeof (Func<,>), typeof (Func<,>), typeof (Func<,,>)}, new[] {typeof (object[]), Tuple.Type, Tuple.Type, queryModel.SelectClause.Selector.Type}); var toList = EnumerableHelper.GetMethod("ToList", new[] { typeof(IEnumerable<>) }, new[] { queryModel.SelectClause.Selector.Type }); var input = Expression.Parameter(typeof (IEnumerable<object>), "input"); var call = Expression.Call(toList, Expression.Call(groupBy, Expression.Call(cast, input), keySelector, elementSelector, Expression.Lambda(resultSelector, key, values))); var lambda = Expression.Lambda(call, input); queryModel.ResultOperators.Add(new ClientSideSelect2(lambda)); var initializers = expressions.Select(e => e.Expression == null ? GetIdentifier(sessionFactory, expressions, e) : ConvertToObject(e.Expression)); queryModel.SelectClause.Selector = Expression.NewArrayInit(typeof (object), initializers); }