2013-07-05 77 views
1

我需要在表達式中使用SqlFunctions.PatIndex。如何動態使用SqlFunctions.PatIndex

Func<IQueryable<T>, KendoFilterDescription, IQueryable<T>> appendFilter = 
       (filteredData, filter) => filteredData.Where(String.Format("System.Data.Objects.SqlClient.SqlFunctions.PatIndex(\"@0\", {0})", filter.Field), ParsePropertyValue(filter)); 

,但我得到一個異常:No property or field 'System' exists in type 'RecordListItem'

如何使用這個功能呢?

+0

您可以精心設計您想要完成的任務嗎?沒有爲你工作:'(filteredData,filter)=> filteredData.Where(f => System.Data.Objects.SqlClient.SqlFunctions.PatIndex(「@ 0」,「」)!= 0);' – eestein

+0

@Mediator:當問一個問題時,特別是如果問題沒有明確說明時,如果您至少可以迴應那些努力爲您提供答案並要求澄清的人員關於你想要達到的目標。你能否請你這樣做。 – Alex

回答

1

由於您的代碼示例中的表達式很長,可能很難看到,但它顯示「Where」子句包含錯誤,因爲它不是可以簡化爲Func<T, bool>的表達式。

我假設這就是爲什麼你得到一個編譯器錯誤。沒有關於KendoFilterDescription是什麼的更多信息,ParsePropertyValue所做的以及您想要使用PatIndex過濾的內容,很難爲您提供一個很好的答案。

所以現在我會盡量胡亂猜測:

  1. 您嘗試使用PATINDEX表達式過濾的IQueryable。
  2. 如果評估的PatIndex表達式不返回0,則「Where」應計算爲true,因此該記錄包含在結果中。
  3. 您希望PatIndex表達式的參數stringPattern等於ParsePropertyValue(filter)的返回值,即要匹配的模式。
  4. 您希望PatIndex表達式的target參數等於名稱爲filter.Field的屬性或字段T的值。

所以作爲一個例子,我們來看一個具有屬性FirstName和LastName的類Person(T)。再假設您要在姓的含有一定文字過濾,然後你想建立一個像一個表達式:

Func<string, string> BuildContainsPattern = phrase => string.Format("%{0}%", phrase); 
Func<IQueryable<Person>, string, IQueryable<Person>> whereFirstNameContains = 
      (data, phrase) => data.Where(p => SqlFunctions.PatIndex(BuildContainsPattern(phrase), p.FirstName) > 0); 

假設這是(基本上)是正確的。我們需要一些構建模塊,這些模塊一起允許我們構建可以傳遞到IQueryable<T>Where子句的Expression<Func<T, bool>>

好吧,那麼困難的部分首先。下面的BuildFilterExpression函數可以爲我們構建這個表達式,只要我們提供(1)作爲PatIndex函數的第一個參數預期的stringPattern和(2)我們希望的實體類型T的屬性名稱用作PatIndex函數的第二個參數。

因此,如果我對ParsePropertyValue(filter)filter.Field表示的假設是正確的,則下面的代碼應使用過濾器提供的設置進行過濾。

using System; 
using System.Linq; 
using System.Reflection; 
using System.Data.Objects.SqlClient; 
using System.Linq.Expressions; 

public class FilterDescription 
{ 
    public enum FilterPatternType 
    { 
     Contains = 1, 
     Range = 2, // [^0-9] 
    } 
    public string Field { get; set; } 
    public string FilterPhrase { get; set; } 
    public FilterPatternType PatternType { get; set; } 
} 

public static class FilterBuilder 
{ 
    private static readonly MethodInfo PatIndexMethod = typeof(SqlFunctions).GetMethod("PatIndex"); 
    private static readonly ConstantExpression ValueZero = Expression.Constant(0, typeof(int?)); 

    public static string ParsePropertyValue(FilterDescription filter) 
    { 
     switch (filter.PatternType) 
     { 
      case FilterDescription.FilterPatternType.Contains: 
       return string.Format("%{0}%", filter.FilterPhrase); 
      case FilterDescription.FilterPatternType.Range: 
       return string.Format("[^{0}]", filter.FilterPhrase); 
      default: 
       throw new InvalidOperationException("Pattern type not supported"); 
     } 
    } 

    public static Expression<Func<TEntity, bool>> BuildFilterExpression<TEntity>(string patternString, string targetProperty) 
    { 
     var patternStringArg = Expression.Constant(patternString); 
     var entityType = Expression.Parameter(typeof(TEntity), "item"); 
     var targetPropertyArg = Expression.PropertyOrField(entityType, targetProperty); 

     MethodCallExpression patIndexCall = Expression.Call(PatIndexMethod, patternStringArg, targetPropertyArg); 

     var isGreaterThanZero = Expression.GreaterThan(patIndexCall, ValueZero); 

     return Expression.Lambda<Func<TEntity, bool>>(isGreaterThanZero, entityType); 
    } 

    public static Expression<Func<TEntity, bool>> BuildFilterExpression<TEntity>(FilterDescription filter) 
    { 
     var pattern = ParsePropertyValue(filter); 
     return BuildFilterExpression<TEntity>(pattern, filter.Field); 
    } 

    public static IQueryable<TEntity> Filter<TEntity>(this IQueryable<TEntity> toFilter, FilterDescription filter) 
    { 
     return toFilter.Where(BuildFilterExpression<TEntity>(filter)); 
    } 
} 

public class Person 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public int Age { get; set; } 
} 

class Program 
{ 
    private static IQueryable<Person> GetPersons() 
    { 
     return (IQueryable<Person>)null; // use your own data. 
    } 

    public static void Main(params string[] args) 
    { 
     var filter = new FilterDescription() 
     { 
      PatternType = FilterDescription.FilterPatternType.Contains, 
      Field = "FirstName", 
      FilterPhrase = "ed" 
     }; 
     var filtered = GetPersons().Filter(filter); 
    } 
} 

顯然,這是可能的,我完全得到了我的胡亂猜測錯了,但我想你會提高你的你想達到什麼樣的描述。