簡體   English   中英

Linq擴展表達式

[英]Linq extending Expressions

我正在嘗試編寫具有以下簽名的ServiceStack.OrmLite.SqlExpressionVisitor的通用通配符搜索:

public static SqlExpressionVisitor<T> WhereWildcardSearch<T> (this SqlExpressionVisitor<T> ev, Expression<Func<T,string>> field, string search)

其中ev是過濾器的其余部分,field是要搜索的字段的getter,搜索是輸入的術語。

通常(非泛型)我會寫以下內容:

if(search.StartsWith('*') && search.EndsWith('*')) 
    ev = ev.Where(x => x.foo.Contains(search.Trim('*')));

當然還有x.foo.StartsWith或EndsWith的變種。

現在我正在尋找類似的東西(偽代碼:)

ev = ev.Where(x => field(x).Contains(search.Trim('*')));

當然我無法直接編譯和調用表達式,因為這應該使用Linq2Sql轉換為Sql。

到目前為止這是我的代碼:

var getFieldExpression = Expression.Invoke (field, Expression.Parameter (typeof (T), "getFieldParam"));
var searchConstant = Expression.Constant (search.Trim('*'));

var inExp = Expression.Call (getFieldExpression, typeof(String).GetMethod("Contains"), searchConstant);
var param = Expression.Parameter (typeof (T), "object");
var exp = Expression.Lambda<Func<T, bool>> (inExp, param);

ev = ev.Where (exp);

請不要告訴我,我應該用$"LIKE %search%"或者其他東西直接編寫SQL - 我知道還有其他方法,但解決這個問題將有助於我理解Linq和Expressions一般而且當我無法解決它。

這是如何做到的(我認為沒有太多額外的解釋,你做錯了什么,但如果沒有 - 請隨時要求澄清):

// extract property name from passed expression
var propertyName = ((MemberExpression)field.Body).Member.Name;            
var param = Expression.Parameter(typeof(T), "object");            
var searchConstant = Expression.Constant(search.Trim('*'));
var contains = typeof(String).GetMethod("Contains");
// object.FieldName.Contains(searchConstant)
var inExp = Expression.Call(Expression.PropertyOrField(param, propertyName), contains, searchConstant);            
// object => object.FieldName.Contains(searchConstant)
var exp = Expression.Lambda<Func<T, bool>>(inExp, param);

回應評論。 你有兩個表達式樹:一個是傳遞給你的,另一個是你正在構建的( exp )。 在這種簡單的情況下,它們都使用相同數量的參數,並且這些參數具有相同的類型( T )。 在這種情況下,您可以重用field表達式樹中的參數,如下所示:

// use the same parameter
var param = field.Parameters[0];
var searchConstant = Expression.Constant(search.Trim('*'));
var contains = typeof(String).GetMethod("Contains");            
// note field.Body here. Your `field` expression is "parameter => parameter.Something"
// but we need just "parameter.Something" expression here
var inExp = Expression.Call(field.Body, contains, searchConstant);
// pass the same parameter to new tree
var exp = Expression.Lambda<Func<T, bool>>(inExp, param);

在更復雜的情況下,您可能需要使用ExpressionVisitor替換一個表達式樹中的參數,以引用另一個(最終)表達式樹中的參數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM