コード例 #1
0
		private SqlNode VisitGroupBy(Expression sequence, LambdaExpression keyLambda, LambdaExpression elemLambda, LambdaExpression resultSelector)
		{
			// Convert seq.Group(elem, key) into
			//
			// SELECT s.key, MULTISET(select s2.elem from seq AS s2 where s.key == s2.key)
			// FROM seq AS s
			//
			// where key and elem can be either simple scalars or object constructions
			//
			SqlSelect seq = this.VisitSequence(sequence);
			seq = this.LockSelect(seq);
			SqlAlias seqAlias = new SqlAlias(seq);
			SqlAliasRef seqAliasRef = new SqlAliasRef(seqAlias);

			// evaluate the key expression relative to original sequence
			_parameterExpressionToSqlExpression[keyLambda.Parameters[0]] = seqAliasRef;
			SqlExpression keyExpr = this.VisitExpression(keyLambda.Body);

			// make a duplicate of the original sequence to use as a foundation of our group multiset
			SqlDuplicator sd = new SqlDuplicator();
			SqlSelect selDup = (SqlSelect)sd.Duplicate(seq);

			// rebind key in relative to the duplicate sequence
			SqlAlias selDupAlias = new SqlAlias(selDup);
			SqlAliasRef selDupRef = new SqlAliasRef(selDupAlias);
			_parameterExpressionToSqlExpression[keyLambda.Parameters[0]] = selDupRef;
			SqlExpression keyDup = this.VisitExpression(keyLambda.Body);

			SqlExpression elemExpr = null;
			SqlExpression elemOnGroupSource = null;
			if(elemLambda != null)
			{
				// evaluate element expression relative to the duplicate sequence
				_parameterExpressionToSqlExpression[elemLambda.Parameters[0]] = selDupRef;
				elemExpr = this.VisitExpression(elemLambda.Body);

				// evaluate element expression relative to original sequence
				_parameterExpressionToSqlExpression[elemLambda.Parameters[0]] = seqAliasRef;
				elemOnGroupSource = this.VisitExpression(elemLambda.Body);
			}
			else
			{
				// no elem expression supplied, so just use an alias ref to the duplicate sequence.
				// this will resolve to whatever was being produced by the sequence
				elemExpr = selDupRef;
				elemOnGroupSource = seqAliasRef;
			}

			// Make a sub expression out of the key.  This will allow a single definition of the 
			// expression to be shared at multiple points in the tree (via SqlSharedExpressionRef's)
			SqlSharedExpression keySubExpr = new SqlSharedExpression(keyExpr);
			keyExpr = new SqlSharedExpressionRef(keySubExpr);

			// construct the select clause that picks out the elements (this may be redundant...)
			SqlSelect selElem = new SqlSelect(elemExpr, selDupAlias, _dominatingExpression);
			selElem.Where = _nodeFactory.Binary(SqlNodeType.EQ2V, keyExpr, keyDup);

			// Finally, make the MULTISET node. this will be used as part of the final select
			SqlSubSelect ss = _nodeFactory.SubSelect(SqlNodeType.Multiset, selElem);

			// add a layer to the original sequence before applying the actual group-by clause
			SqlSelect gsel = new SqlSelect(new SqlSharedExpressionRef(keySubExpr), seqAlias, _dominatingExpression);
			gsel.GroupBy.Add(keySubExpr);
			SqlAlias gselAlias = new SqlAlias(gsel);

			SqlSelect result = null;
			if(resultSelector != null)
			{
				// Create final select to include construction of group multiset
				// select new Grouping { Key = key, Group = Multiset(select elem from seq where match) } from ...
				Type elementType = typeof(IGrouping<,>).MakeGenericType(keyExpr.ClrType, elemExpr.ClrType);

				SqlExpression keyGroup = new SqlGrouping(elementType, _typeProvider.From(elementType), keyExpr, ss, _dominatingExpression);
				SqlSelect keyGroupSel = new SqlSelect(keyGroup, gselAlias, _dominatingExpression);
				SqlAlias kgAlias = new SqlAlias(keyGroupSel);
				SqlAliasRef kgAliasRef = new SqlAliasRef(kgAlias);

				_parameterExpressionToSqlExpression[resultSelector.Parameters[0]] = _nodeFactory.Member(kgAliasRef, elementType.GetProperty("Key"));
				_parameterExpressionToSqlExpression[resultSelector.Parameters[1]] = kgAliasRef;

				// remember the select that has the actual group (for optimizing aggregates later)
				_sqlNodeToGroupInfo[kgAliasRef] = new GroupInfo { SelectWithGroup = gsel, ElementOnGroupSource = elemOnGroupSource };

				SqlExpression resultExpr = this.VisitExpression(resultSelector.Body);
				result = new SqlSelect(resultExpr, kgAlias, _dominatingExpression);

				// remember the select that has the actual group (for optimizing aggregates later)
				_sqlNodeToGroupInfo[resultExpr] = new GroupInfo { SelectWithGroup = gsel, ElementOnGroupSource = elemOnGroupSource };
			}
			else
			{
				// Create final select to include construction of group multiset
				// select new Grouping { Key = key, Group = Multiset(select elem from seq where match) } from ...
				Type elementType = typeof(IGrouping<,>).MakeGenericType(keyExpr.ClrType, elemExpr.ClrType);

				SqlExpression resultExpr = new SqlGrouping(elementType, _typeProvider.From(elementType), keyExpr, ss, _dominatingExpression);
				result = new SqlSelect(resultExpr, gselAlias, _dominatingExpression);

				// remember the select that has the actual group (for optimizing aggregates later)
				_sqlNodeToGroupInfo[resultExpr] = new GroupInfo { SelectWithGroup = gsel, ElementOnGroupSource = elemOnGroupSource };
			}

			return result;
		}
コード例 #2
0
ファイル: SqlVisitor.cs プロジェクト: modulexcite/LinqToSQL2
 internal virtual SqlExpression VisitGrouping(SqlGrouping g) {
     g.Key = this.VisitExpression(g.Key);
     g.Group = this.VisitExpression(g.Group);
     return g;
 }
コード例 #3
0
		private Type GenerateGrouping(SqlGrouping grp)
		{
			Type[] typeArgs = grp.ClrType.GetGenericArguments();

			this.GenerateExpressionForType(grp.Key, typeArgs[0]);
			this.Generate(grp.Group);

			Type orbType = typeof(ObjectMaterializer<>).MakeGenericType(this.compiler.DataReaderType);
			MethodInfo miCreateGroup = TypeSystem.FindStaticMethod(orbType, "CreateGroup", new Type[] { typeArgs[0], typeof(IEnumerable<>).MakeGenericType(typeArgs[1]) }, typeArgs);
			Diagnostics.Debug.Assert(miCreateGroup != null);
			gen.Emit(OpCodes.Call, miCreateGroup);

			return miCreateGroup.ReturnType;
		}
コード例 #4
0
		internal override SqlExpression VisitGrouping(SqlGrouping g)
		{
			if(!_isDebugMode)
			{
				throw Error.InvalidFormatNode("Grouping");
			}
			_commandStringBuilder.Append("Group(");
			this.Visit(g.Key);
			_commandStringBuilder.Append(", ");
			this.Visit(g.Group);
			_commandStringBuilder.Append(")");
			return g;
		}
コード例 #5
0
		internal override SqlExpression VisitGrouping(SqlGrouping g)
		{
			SqlGrouping n = new SqlGrouping(g.ClrType, g.SqlType,
				this.VisitExpression(g.Key), this.VisitExpression(g.Group), g.SourceExpression
				);
			return n;
		}
コード例 #6
0
		internal override SqlExpression VisitGrouping(SqlGrouping g)
		{
			g.Key = this.VisitNamedExpression(g.Key, "Key");
			g.Group = this.VisitNamedExpression(g.Group, "Group");
			return g;
		}
コード例 #7
0
		internal override SqlExpression VisitGrouping(SqlGrouping g) {
			g.Key = this.FetchExpression(g.Key);
			g.Group = this.FetchExpression(g.Group);
			return g;
		}