public static void ReWrite(QueryModel queryModel, ISessionFactory sessionFactory)
        {
            var nsqmv = new NestedSelectDetector(sessionFactory);

            nsqmv.VisitExpression(queryModel.SelectClause.Selector);
            if (!nsqmv.HasSubqueries)
            {
                return;
            }

            var elementExpression = new List <ExpressionHolder>();
            var group             = Expression.Parameter(typeof(IGrouping <Tuple, Tuple>), "g");

            var replacements = new Dictionary <Expression, Expression>();

            foreach (var expression in nsqmv.Expressions)
            {
                var processed = ProcessExpression(queryModel, sessionFactory, expression, elementExpression, group);
                if (processed != null)
                {
                    replacements.Add(expression, processed);
                }
            }

            var key = Expression.Property(group, "Key");

            var expressions = new List <ExpressionHolder>();

            var identifier = GetIdentifier(sessionFactory, new QuerySourceReferenceExpression(queryModel.MainFromClause));

            var rewriter = new SelectClauseRewriter(key, expressions, identifier, replacements);

            var resultSelector = rewriter.VisitExpression(queryModel.SelectClause.Selector);

            elementExpression.AddRange(expressions);

            var keySelector = CreateSelector(elementExpression, 0);

            var elementSelector = CreateSelector(elementExpression, 1);

            var groupBy = EnumerableHelper.GetMethod("GroupBy",
                                                     new[] { typeof(IEnumerable <>), typeof(Func <,>), typeof(Func <,>) },
                                                     new[] { typeof(object[]), typeof(Tuple), typeof(Tuple) });

            var input = Expression.Parameter(typeof(IEnumerable <object>), "input");

            var lambda = Expression.Lambda(
                Expression.Call(groupBy,
                                Expression.Call(CastMethod, input),
                                keySelector,
                                elementSelector),
                input);

            queryModel.ResultOperators.Add(new ClientSideSelect2(lambda));
            queryModel.ResultOperators.Add(new ClientSideSelect(Expression.Lambda(resultSelector, @group)));

            var initializers = elementExpression.Select(e => ConvertToObject(e.Expression));

            queryModel.SelectClause.Selector = Expression.NewArrayInit(typeof(object), initializers);
        }
		public static void ReWrite(QueryModel queryModel, ISessionFactory sessionFactory)
		{
			var nsqmv = new NestedSelectDetector(sessionFactory);
			nsqmv.VisitExpression(queryModel.SelectClause.Selector);
			if (!nsqmv.HasSubqueries)
				return;

			var elementExpression = new List<ExpressionHolder>();
			var group = Expression.Parameter(typeof (IGrouping<Tuple, Tuple>), "g");
			
			var replacements = new Dictionary<Expression, Expression>();
			foreach (var expression in nsqmv.Expressions)
			{
				var processed = ProcessExpression(queryModel, sessionFactory, expression, elementExpression, group);
				if (processed != null)
					replacements.Add(expression, processed);
			}

			var key = Expression.Property(group, "Key");

			var expressions = new List<ExpressionHolder>();

			var identifier = GetIdentifier(sessionFactory, new QuerySourceReferenceExpression(queryModel.MainFromClause));

			var rewriter = new SelectClauseRewriter(key, expressions, identifier, replacements);

			var resultSelector = rewriter.VisitExpression(queryModel.SelectClause.Selector);

			elementExpression.AddRange(expressions);

			var keySelector = CreateSelector(elementExpression, 0);

			var elementSelector = CreateSelector(elementExpression, 1);

			var groupBy = EnumerableHelper.GetMethod("GroupBy",
													 new[] { typeof (IEnumerable<>), typeof (Func<,>), typeof (Func<,>) },
													 new[] { typeof (object[]), typeof (Tuple), typeof (Tuple) });

			var input = Expression.Parameter(typeof (IEnumerable<object>), "input");

			var lambda = Expression.Lambda(
				Expression.Call(groupBy,
								Expression.Call(CastMethod, input),
								keySelector,
								elementSelector),
				input);

			queryModel.ResultOperators.Add(new ClientSideSelect2(lambda));
			queryModel.ResultOperators.Add(new ClientSideSelect(Expression.Lambda(resultSelector, @group)));

			var initializers = elementExpression.Select(e => ConvertToObject(e.Expression));

			queryModel.SelectClause.Selector = Expression.NewArrayInit(typeof (object), initializers);
		}
		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);
		}
        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);
        }