2012-05-23 23 views
5

在linq to Entities中,我們需要一種類似「sql like」的方法。我們已經實現了自己的擴展方法來IQueryable的,因爲contains方法爲我們不行,因爲不接受像模式「%A%B%」linq to Entities中where子句的擴展方法

創建的代碼是:

private const char WildcardCharacter = '%'; 

public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> _source, Expression<Func<TSource, string>> _valueSelector, string _textSearch) 
{ 
    if (_valueSelector == null) 
    { 
     throw new ArgumentNullException("valueSelector"); 
    } 

     return _source.Where(BuildLikeExpressionWithWildcards(_valueSelector, _textSearch)); 
} 

private static Expression<Func<TSource, bool>> BuildLikeExpressionWithWildcards<TSource>(Expression<Func<TSource, string>> _valueSelector, string _textToSearch) 
{ 
    var method = GetPatIndexMethod(); 

    var body = Expression.Call(method, Expression.Constant(WildcardCharacter + _textToSearch + WildcardCharacter), _valueSelector.Body); 

    var parameter = _valueSelector.Parameters.Single(); 
    UnaryExpression expressionConvert = Expression.Convert(Expression.Constant(0), typeof(int?)); 
    return Expression.Lambda<Func<TSource, bool>> (Expression.GreaterThan(body, expressionConvert), parameter); 
} 

private static MethodInfo GetPatIndexMethod() 
{ 
    var methodName = "PatIndex"; 

    Type stringType = typeof(SqlFunctions); 
    return stringType.GetMethod(methodName); 
} 

這正常工作和代碼在SqlServer中完全執行,但現在我們將使用內部where子句,因爲這擴展方法:

myDBContext.MyObject.Where(o => o.Description.Like(patternToSearch) || o.Title.Like(patterToSerch)); 

的問題是,在WHERE子句中使用的方法有,如果是用來返回布爾結果運營商喜歡'||' ,並且我不知道如何使我創建的代碼返回一個布爾值並使代碼在sqlserver中執行。我想我必須通過BuildLinqExpression方法將返回的Expression轉換爲bool,但我不知道如何去做

總結起來!首先,可以在Linq中創建我們自己的擴展方法來執行SqlServer中的代碼?如果這是可能的我該怎麼做呢?

感謝您的幫助。

+2

你有沒有嘗試使用['SqlMethods.Like'(HTTP:// MSDN。 microsoft.com/en-us/library/system.data.linq.sqlclient.sqlmethods.like.aspx)? – dasblinkenlight

+0

@dasblinkenlight SqlMethods不能在Linq to Entity中使用。 –

回答

3

不,您無法教育EF處理您的自定義擴展方法,即使您有代碼可以構建表示可用於EF的表達式。

或者:

  • 直接使用SqlFunctions方法在你的EF Where表達
  • 使用ExpressionVisitor將多個表達式組合成一個複合(OrElse/AndAlso)的表達(注意,這不會幫助你代碼就像你想要的,但是它會讓你使用你的兩種方法並在它們上執行||-雖然看起來很複雜,但是)

第一個更簡單,更清晰。

+0

如果我沒有錯SqlMethods不能用於實體的linq,我已經嘗試過並崩潰了。另一個用戶報告相同http://stackoverflow.com/questions/2584598/linq-sqlmethods-like-fails –

+0

@Marc對不起,我可能是指'SqlFunctions' - 即你已經使用的引擎蓋下的代碼 –

+0

@Marc和:如果那是你自己的班級,那麼:你無能爲力。也許只需寫入SQL並通過* EF將其壓下*而不是嘗試編寫LINQ。 –

2

在這裏找到答案:https://stackoverflow.com/a/10726256/84206

他的代碼:http://pastebin.com/4fMjaCMV

允許您標記的擴展方法爲[Expandable],因此只要表達它返回與linq2entities作品,將與內更換您的函數調用表達。需要注意的是直列lambda表達式給出錯誤,所以我不得不把他們定義爲局部變量或靜態變量,如IsCurrent變量這裏:

static Expression<Func<PropertyHistory, bool>> IsCurrent = (p) => p.Starts <= DateTime.Now; 

[ExpandableMethod] 
public static IQueryable<PropertyHistory> AsOf(this IQueryable<PropertyHistory> source) 
{ 
    return source.Where(IsCurrent); 
}