Linq to Sql : 动态构造Expression进行动态查询
??? 前一篇在介紹動態查詢時,提到一個問題:如何根據用戶的輸入條件,動態構造這個過濾條件表達式呢?
Expression<Func<ProductExt, bool>> predicate t => t.ProductName.Contains("che") && t.UnitPrice >= 22;
??? 理想情況下,我希望可以像下面這樣來構造predicate,這樣,我們就可以使用&、| 、&=、|=來任意拼接過濾條件了:
1: Expression<Func<ProductExt, bool>> predicate = null; 2: predicate (t => t.ProductName.Contains("che")) (t => t.UnitPrice >= 22);??? 但是理想與現實之間,似乎總有不可逾越的鴻溝……
?
??? 前面的代碼中,我們總是要寫一常串Expression<Func<T, bool>>,寫得都有點兒煩了,我妄想自定義一個類型,這樣就不用每次都寫這么長了,然后再針對這個自定義類型再進行運算符重載……然后我發現,Expression<Delegate>是密封類型(sealed),不給重載,沒辦法,只好老老實實的寫,運算符重載也泡湯了。
?
?? 無奈之下,只好實現了下面的這種方式,勉強湊合用著:
1: Expression<Func<, bool>> predicate = null; 2: predicate = predicate.AndAlso(p => p.CompanyName.Length > 2) 3: .OrElse((p) => p.ProductName.Contains("che")) 4: .AndAlso(( p) => p.UnitPrice >= 22);??? 運算得到的結果如下:p => (((p.CompanyName.Length > 2) || p.ProductName.Contains("che")) && (p.UnitPrice >= 22))
??? 有了這個OrElse和AndAlso擴展,我們就可以對Expression<Func<T, bool>>為所欲為了……
??? 不過跟之前文章中提到的一樣,這里有個限制:雖然我們的Expression中,第一個可以凡泛型參數可以傳任意值(譬如傳ProductExt或Products或其他的,可以不必要求是同一種類型),但條件中用到的對象屬性(譬如CompanyName、ProductName、UnitPrice ),必須在T中存在同名屬性。
?
?2010-12-31更新:
?更新了ParameterConverter類,之前對二元運算符的右側和方法參數直接求值的,所以不能處理Expression中含有&& 和 || 等二元運算符、及方法參數中包含Expression參數(例如list.Contains(p.CompanyName))的情況;現在增加了參數訪問計數,如果二元表達式&&和||、及方法的參數中不包含Expression參數,則進行求值,否則不求值。代碼如下:
?2?????{
?3?????????protected?LambdaExpression?SourceExpression?{?get;?set;?}
?4?????????protected?ParameterExpression?Parameter?{?get;?set;?}
?5?????????protected?bool?UseOuterParameter?=?false;
?6?
?7?????????public?ParameterConverter(LambdaExpression?expression)
?8?????????{
?9?????????????this.SourceExpression?=?(LambdaExpression)expression;
10?????????}
11?
12?????????public?ParameterConverter(LambdaExpression?expression,?ParameterExpression?parameter)?:?this(expression)
13?????????{
14?????????????this.Parameter?=?parameter;
15?????????????this.UseOuterParameter?=?true;
16?????????}
17?
18?????????public?LambdaExpression?Replace(Type?targetType)
19?????????{
20?????????????if?(this.SourceExpression?==?null)
21?????????????????return?null;
22?
23?????????????if?(!this.UseOuterParameter)
24?????????????????this.Parameter?=?Expression.Parameter(targetType,?this.SourceExpression.Parameters[0].Name);
25?
26?????????????Expression?body?=?this.Visit(this.SourceExpression.Body);
27?????????????this.SourceExpression?=?Expression.Lambda(body,?this.Parameter);
28?????????????return?this.SourceExpression;
29?????????}
30?
31?????????protected?override?Expression?VisitParameter(ParameterExpression?p)
32?????????{
33?????????????return?this.Parameter;
34?????????}
35?
36?????????protected?override?Expression?VisitMemberAccess(MemberExpression?m)
37?????????{
38?????????????Expression?exp?=?this.Visit(m.Expression);
39?????????????PropertyInfo?propertyInfo?=?m.Member?as?PropertyInfo;
40?????????????return?propertyInfo?==?null???m?:?Expression.Property(exp,?propertyInfo.Name);
41?????????}
42?
43?????????protected?override?Expression?VisitBinary(BinaryExpression?b)
44?????????{
45?????????????Expression?left?=?this.Visit(b.Left);
46?????????????Expression?right?=?Calc(b.Right);//對二元運算符右邊的表達式進行求值
47?????????????Expression?conversion?=?this.Visit(b.Conversion);
48?????????????if?(b.NodeType?==?ExpressionType.Coalesce?&&?b.Conversion?!=?null)
49?????????????????return?Expression.Coalesce(left,?right,?conversion?as?LambdaExpression);
50?????????????else
51?????????????????return?Expression.MakeBinary(b.NodeType,?left,?right,?b.IsLiftedToNull,?b.Method);
52?????????}
53?
54?????????protected?override?ReadOnlyCollection<Expression>?VisitExpressionList(
55?????????????????ReadOnlyCollection<Expression>?original)
56?????????{
57?????????????if?(original?==?null?||?original.Count?==?0)
58?????????????????return?original;
59?
60?????????????//對參數進行求值運算
61?????????????List<Expression>?list?=?new?List<Expression>();
62?????????????for?(int?i?=?0,?n?=?original.Count;?i?<?n;?i++)
63?????????????{
64?????????????????list.Add(Calc(original[i]));?//對調用函數的輸入參數進行求值
65?????????????}
66?????????????return?list.AsReadOnly();
67?????????}
68?
69?????????private?static?Expression?Calc(Expression?e)
70?????????{
71?????????????LambdaExpression?lambda?=?Expression.Lambda(e);
72?????????????return?Expression.Constant(lambda.Compile().DynamicInvoke(null),?e.Type);
73?????????}
74?????}
?
? 最后,上代碼:LinqToSqlExtension
?博客園的文件貌似有緩存,刪掉重新上傳,總是覆蓋不了,只好單獨上傳了 ParameterConverter.rar
轉載于:https://www.cnblogs.com/happyhippy/archive/2010/01/28/1658410.html
總結
以上是生活随笔為你收集整理的Linq to Sql : 动态构造Expression进行动态查询的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在看完《Programming in L
- 下一篇: OpenGL帧缓存对象(FBO:Fram