[英]How Do I Write This Nested Query With Expression Trees?
我有一個LINQ-to-SQL查詢,我需要為涉及泛型和動態類型的生產代碼編寫。 在SO的其他人的幫助下,我已經能夠確定我需要使用表達式樹創建查詢。 為了熟悉表達式樹,我首先嘗試編寫一個更簡單的靜態類型版本,但是我在查找嵌套查詢部分時遇到了麻煩。
我一直在使用MSDN作為參考,主要是本文 。
這是將在示例查詢中使用的類型。 它是一個類的簡化版本,用於從SQL數據庫創建具有動態列數的網格。
public class PivotElement {
public int Key { get; set; }
public string DataField { get; set; }
public string ColumnText { get; set; }
}
這是我想最終構建的查詢,用擴展語法編寫:
IQueryable<PivotElement> iQ = ...;
var copy = iQ;
// filterColumn and filterValue are strings that were passed in
copy = copy.Where(
pe1 => theIQ.Where(
pe2 =>
pe1.Key == pe1.Key &&
pe2.DataField == filterColumn &&
pgr2.ColumnText.Contains( filterValue )
).Any()
);
此參數在元素旋轉之前過濾掉在請求的列中不包含請求的文本的行。
這是我到目前為止所得到的。 我認為這是最正確的,但我不確定如何表明內部Where
應始終在theIQ
上theIQ
。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace IQueryableWhereTypeChange {
class Program {
static void Main( string[] args ) {
var list = new List<PivotElement>() {
new PivotElement() {
Key = 1, DataField = "FirstName", ColumnText = "Bob"
},
new PivotElement() {
Key = 1, DataField = "LastName", ColumnText = "Sanders"
},
new PivotElement() {
Key = 2, DataField = "FirstName", ColumnText = "Bob"
},
new PivotElement() {
Key = 2, DataField = "LastName", ColumnText = "Smith"
},
new PivotElement() {
Key = 3, DataField = "FirstName", ColumnText = "John"
},
new PivotElement() {
Key = 3, DataField = "LastName", ColumnText = "Smith"
}
};
var theIQ = list.AsQueryable();
var iQCopy = theIQ;
var elementType = typeof( PivotElement );
var delegateType = typeof( Func<PivotElement, bool> );
var filterColumn = "LastName";
var filterValue = "Smith";
// Query is
// iQCopy = iQCopy.Where(
// pe1 => iQ.Where(
// pe2 =>
// pe1.Key == pe1.Key &&
// pe2.DataField == filterColumn &&
// pgr2.ColumnText.Contains( filterValue )
// ).Any()
//);
// So all the elements for keys 2 and 3 should be in the
// result set, as those keys have a last name of Smith
// build pe1
Type elementType = typeof( PivotElement );
ParameterExpression pe1 = Expression.Parameter( elementType, "pe1" );
// build pe2
ParameterExpression pe2 = Expression.Parameter( elementType, "pe2" );
// pe1.Key
Expression pe1KeyProp = Expression.Property(
pe1, elementType.GetProperty( "Key" )
);
// pe2.Key
Expression pe2KeyProp = Expression.Property(
pe2, elementType.GetProperty( "Key" )
);
// build pe1.Key == pe2.Key
Expression keyEquals = Expression.Equal( pe1KeyProp, pe2KeyProp );
// build pe2.Datafield
Expression pe2Datafield = Expression.Property(
pe2, elementType.GetProperty( "DataField" )
);
// build pe2.DataField == filterColumn
Expression columnExpression = Expression.Constant( filterColumn );
Expression dataEquals = Expression.Equal(
pe2Datafield, columnExpression
);
// build pe2.ColumnText
Expression pe2ColumnText = Expression.Property(
pe2, elementType.GetProperty( "ColumnText" )
);
// build pe2.ColumnText.Contains( filterValue )
Type stringType = typeof(string);
Expression valueExpression = Expression.Constant( filterValue );
Expression textContains = Expression.Call(
pe2ColumnText,
stringType.GetMethod(
"Contains",
new Type[] { stringType } ),
new Expression[] { valueExpression }
);
// build pe1.Key == pe2.Key &&
// pe2.DataField == filterColumn &&
// pe2.ColumnText.Contains( filterValue )
Expression innerCondition = Expression.AndAlso(
keyEquals, Expression.AndAlso( dataEquals, textContains )
);
// build theIQ.Where( pe2 => innerCondition )
// build theIQ.Where( pe2 => innerCondition ).Any()
// build iQCopy.Where( pe1 => anyCall )
// create the final query
// enumerate results
foreach( var pe in results ) {
Console.WriteLine(
"Key: " + pe.Key +
", DataField: " + pe.DataField +
", ColumnText: " + pe.ColumnText
);
}
}
}
public class PivotElement {
public int Key { get; set; }
public string DataField { get; set; }
public string ColumnText { get; set; }
}
}
丟失的一點擊中我,因為我得到了所有格式化的問題。 因為我已經把它全部輸了,所以我繼續發布它。 如果有人有興趣,這里有缺失的位:
// build theIQ.Where( pe2 => innerCondition )
Type queryableType = typeof( Queryable );
var delegateType = typeof( Func<PivotElement, bool> );
MethodCallExpression innerWhere = Expression.Call(
queryableType,
"Where",
new Type[] { elementType },
new Expression[] {
theIQ.Expression,
Expression.Lambda(
delegateType, innerCondition, new ParameterExpression[] { pe2 }
)
}
);
// build theIQ.Where( pe2 => innerWhere ).Any()
MethodCallExpression anyCall = Expression.Call(
queryableType, "Any", new Type[] { elementType }, innerWhere
);
// build iQCopy.Where( pe1 => anyCall )
MethodCallExpression outerWhere = Expression.Call(
queryableType,
"Where",
new Type[] { elementType },
new Expression[] {
iQCopy.Expression,
Expression.Lambda(
delegateType, anyCall, new ParameterExpression[] { pe1 }
)
}
);
// create the final query
var results = iQCopy.Provider.CreateQuery<PivotElement>( outerWhere );
theIQ.Expression
告訴它使用來自theIQ
查詢結構, iQCopy.Expression
告訴它使用來自iQCopy
查詢結構,最終的iQCopy.Provider
告訴它將構造的查詢應用於實際的iQCopy
實例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.