2016-09-05 8 views
1

私は検索ページを実装しています。ここでは、さまざまなフィルタを使用して結果をフィルタリングできます。フィルタリングを行うためにラムダ式を検索レイヤーに渡す必要があります。 私の問題は、ラムダ式を動的に構築する方法がわかりません。カスタム演算子を使ってラムダ式を結合する

AndAlso()を使用して式を結合しようとしましたが、ラムダ式がboolを返さないため動作しません。 私はExpressionVisitorを実装する必要があると思っています。

// The custom operator for AFilterType 
public static AFilterType operator &(AFilterType first, AFilterType second) 
{ 
    return new AndFilter(AFilterType.GetFilters<AndFilter>(first, second)); 
} 

// Here's a simplified version of what I'm trying to do 
var filterInput = new FilterInput() { FirstName = "John", LastName = "Doe" }; 

// Using Match() which is a AFilterType method 
Expression<Func<Person, AFilterType>> firstNameFilterExpression = x => x.firstName.Match(filterInput.FirstName); 
Expression<Func<Person, AFilterType>> lastNameFilterExpression = x => x.LastName.Match(filterInput.LastName); 

// How can I combine those 2 expressions into 1 single Expression at runtime using the custom operator '&' (not the bool '&&'). 
// Combined Expression should be like this. 
Expression<Func<Person, AFilterType>> combinedFilterExpression = x => x.firstName.Match(filterInput.FirstName) & x.LastName.Match(filterInput.LastName); 
+0

仕様パターンを見てください。 –

+0

私は使用しているAPIに便利な機能を見つけました(Episerver FIND)。 FINDは弾性検索に基づいています。 combinedFilterExpressionを動的に構築するために使用できるFilterExpressionParserがありました。私の質問のタグを更新し、私のコードを以下に掲載します。 – Pegu

答えて

1

私が働いている実際のドメインに関する詳細は慎重に除外しました。これは私の質問をより一般的にし、表現に焦点を当てる試みでした。 しかし、私が使用しているAPI(Episerver FIND)にはFilterExpressionParserが用意されていました。

ここでは、複合フィルタを作成して適用する関数です。

private void MechanicalPropertiesFilter(SteelNavigatorForm form, ref ITypeSearch<SteelGradeVariantPage> search) 
    { 
     FilterExpressionParser filterExpressionParser = new FilterExpressionParser(SearchClient.Instance.Conventions); 
     Filter combinedFilter = null; 

     // Dimension 
     if (form.DimensionThickness > 0) 
     { 
      var dimensionFilter = filterExpressionParser.GetFilter<MechanicalProperties>(m => m.DimensionInMillimeterMin.LessThan(form.DimensionThickness) 
      & m.DimensionInMillimeterMax.GreaterThan(form.DimensionThickness)); 

      combinedFilter = (combinedFilter == null) ? dimensionFilter : combinedFilter & dimensionFilter; 
     } 

     // Yield strength 
     if (form.YieldStrengthMin > 0) 
     { 
      var yieldStrengthFilter = filterExpressionParser.GetFilter<MechanicalProperties>(m => m.YieldStrengh.GreaterThan(form.YieldStrengthMin)); 
      combinedFilter = (combinedFilter == null) ? yieldStrengthFilter : combinedFilter & yieldStrengthFilter; 
     } 

     // Tensile strength 
     if (form.TensileStrengthMin > 0 | form.TensileStrengthMax > 0) 
     { 
      var tensileStrengthMin = (form.TensileStrengthMin == 0) ? double.MinValue : form.TensileStrengthMin; 
      var tensileStrengthMax = (form.TensileStrengthMax == 0) ? double.MaxValue : form.TensileStrengthMax; 
      var tensileStrengthFilter = filterExpressionParser.GetFilter<MechanicalProperties>(m => m.TensileStrengthMin.InRangeInclusive(tensileStrengthMin, tensileStrengthMax) | m.TensileStrengthMax.InRangeInclusive(tensileStrengthMin, tensileStrengthMax)); 

      combinedFilter = (combinedFilter == null) ? tensileStrengthFilter : combinedFilter & tensileStrengthFilter; 
     } 

     // Elongation 
     if (form.Elongation > 0) 
     { 
      var elongationFilter = filterExpressionParser.GetFilter<MechanicalProperties>(m => m.ElongationA5Percentage.GreaterThan(form.Elongation)); 

      combinedFilter = (combinedFilter == null) ? elongationFilter : combinedFilter & elongationFilter; 
     } 

     // Hardness 
     if (form.HardnessMin > 0 || form.HardnessMax > 0) 
     { 
      var max = (form.HardnessMax == 0) ? double.MaxValue : form.HardnessMax; 

      var hardnessFilter = filterExpressionParser.GetFilter<MechanicalProperties>(m => m.HardnessScaleGuid.Match(form.HardnessMethod) & (
       m.HardnessMin.InRangeInclusive(form.HardnessMin, max) 
       | m.HardnessMax.InRangeInclusive(form.HardnessMin, max))); 

      combinedFilter = (combinedFilter == null) ? hardnessFilter : combinedFilter & hardnessFilter; 
     } 

     if (combinedFilter != null) 
     { 
      NestedFilterExpression<SteelGradeVariantPage, MechanicalProperties> mechanicalFilterExpression = new NestedFilterExpression<SteelGradeVariantPage, MechanicalProperties>(v => v.MechanicalProperties, ((MechanicalProperties item) => combinedFilter), search.Client.Conventions); 

      search = search.Filter(mechanicalFilterExpression.NestedFilter); 
     } 
    } 
2

私はかつて同じ問題を抱えていたと私はLinqKitと反射を少し(私はEntityFrameworkプロジェクトでこれを使用しましたが、必要に応じて、それは、他のタイプに適合させることができる)を使用して、それを解決しました。私は下に私のストリップされたコードを投稿しようとします(あまりにも長すぎないことを望みます)。

前処理:LinqKit(https://www.nuget.org/packages/LinqKitまたはvia NuGet)バージョン1.1.7.2以降が含まれています。

コードはサブディレクトリに複数のファイルで構成されています

  • インタフェース
  • 枠組み
  • 拡張

インターフェース\ IPredicateParser.cs

using System; 
using System.Collections.Generic; 

namespace LambdaSample.Interfaces 
{ 
    // Used to defined IPredicateParser for parsing predicates 
    public interface IPredicateParser 
    { 
     bool Parse(string text, bool rangesAllowed, Type definedType); 

     List<IPredicateItem> Items { get; } 
    } 
} 

インターフェース\ IPredicateItem.cs

namespace LambdaSample.Interfaces 
{ 
    public interface IPredicateItem 
    { 
     bool IsValid { get; } 
    } 
} 

フレームワークの\ PredicateItemSingle.cs

using LambdaSample.Interfaces; 

namespace LambdaSample.Framework 
{ 
    /// <summary> 
    /// Item for single predicate (e.g. "44") 
    /// </summary> 
    public class PredicateItemSingle : IPredicateItem 
    { 
     public PredicateItemSingle() 
     { 

     } 

     public bool IsValid => Value != null; 


     public object Value { get; set; } 
    } 
} 

Frameworkの\ PredicateItemRange.cs

using LambdaSample.Interfaces; 

namespace LambdaSample.Framework 
{ 
    /// <summary> 
    /// Item for range predicates (e.g. "1-5") 
    /// </summary> 
    public class PredicateItemRange : IPredicateItem 
    { 
     public PredicateItemRange() 
     { 

     } 

     public bool IsValid => Value1 != null && Value2 != null; 

     public object Value1 { get; set; } 

     public object Value2 { get; set; } 
    } 
} 

Frameworkの\ PredicateParser.cs

using System; 
using System.Collections.Generic; 
using System.Globalization; 
using LambdaSample.Extensions; 
using LambdaSample.Interfaces; 

namespace LambdaSample.Framework 
{ 
    /// <summary> 
    /// Simple parser for text used in search fields for 
    /// searching through records or any values 
    /// </summary> 
    public class PredicateParser : IPredicateParser 
    { 
     private enum RangeType 
     { 
      None, 
      From, 
      To 
     } 

     public PredicateParser() 
     { 
      Items = new List<IPredicateItem>(); 
     } 

     public bool Parse(string text, bool rangesAllowed, Type definedType) 
     { 
      Items.Clear(); 

      if (string.IsNullOrWhiteSpace(text)) 
       return true; 

      var result = true; 

      var items = text.Split(','); 
      foreach (var item in items) 
      { 
       object val1, val2; 
       bool isRange; 
       var ranges = item.Split('-'); 
       if (rangesAllowed && ranges.Length == 2) // Range is only when ranges are allowed and length is 2, otherwise its single value. 
       { 
        object val1Temp, val2Temp; 
        if (ParseValue(ranges[0], definedType, RangeType.From, out isRange, out val1, out val1Temp) && 
         ParseValue(ranges[1], definedType, RangeType.To, out isRange, out val2, out val2Temp)) 
        { 
         Items.Add(new PredicateItemRange { Value1 = val1, Value2 = val2, }); 
        } 
        else 
        { 
         result = false; 
        } 
       } 
       else 
       { 
        if (ParseValue(item, definedType, RangeType.None, out isRange, out val1, out val2)) 
        { 
         if (isRange) 
         { 
          Items.Add(new PredicateItemRange { Value1 = val1, Value2 = val2, }); 
         } 
         else 
         { 
          Items.Add(new PredicateItemSingle { Value = val1, }); 
         } 
        } 
        else 
        { 
         result = false; 
        } 
       } 
      } 

      return result; 
     } 

     private bool ParseValue(string value, Type definedType, RangeType rangeType, out bool isRange, out object result, out object result2) 
     { 
      result = null; 
      result2 = null; 
      isRange = false; 
      if (string.IsNullOrWhiteSpace(value)) 
       return false; 

      // Enums are also treated like ints! 
      if (definedType == typeof(int) || definedType.IsEnum) 
      { 
       int val; 
       if (!int.TryParse(value, out val)) 
        return false; 
       result = val; 
       return true; 
      } 

      if (definedType == typeof(long)) 
      { 
       long val; 
       if (!long.TryParse(value, out val)) 
        return false; 
       result = val; 
       return true; 
      } 

      if (definedType == typeof(decimal)) 
      { 
       decimal val; 
       if (!decimal.TryParse(value, NumberStyles.Number^NumberStyles.AllowThousands, new CultureInfo("sl-SI"), out val)) 
        return false; 
       result = val; 
       return true; 
      } 

      if (definedType == typeof(DateTime)) 
      { 
       int year, month, yearMonth; 
       if (value.Length == 4 && int.TryParse(value, out year) && year >= 1000 && year <= 9999) // If only year, we set whole year's range (e.g. 2015 ==> 2015-01-01 00:00:00.0000000 - 2015-12-31 23:59:59.9999999 
       { 
        // Default datetime for From range and if no range 
        result = new DateTime(year, 1, 1); 
        switch (rangeType) 
        { 
         case RangeType.None: 
          result2 = ((DateTime)result).AddYears(1).AddMilliseconds(-1); 
          isRange = true; 
          break; 
         case RangeType.To: 
          result = ((DateTime)result).AddYears(1).AddMilliseconds(-1); 
          break; 
        } 
        return true; 
       } 
       if (value.Length == 6 && int.TryParse(value, out yearMonth) && yearMonth >= 100001 && yearMonth <= 999912) // If only year and month, we set whole year's range (e.g. 201502 ==> 2015-02-01 00:00:00.0000000 - 2015-02-28 23:59:59.9999999 
       { 
        year = Convert.ToInt32(yearMonth.ToString().Substring(0, 4)); 
        month = Convert.ToInt32(yearMonth.ToString().Substring(4, 2)); 

        // Default datetime for From range and if no range 
        result = new DateTime(year, month, 1); 
        switch (rangeType) 
        { 
         case RangeType.None: 
          result2 = ((DateTime)result).AddMonths(1).AddMilliseconds(-1); 
          isRange = true; 
          break; 
         case RangeType.To: 
          result = ((DateTime)result).AddMonths(1).AddMilliseconds(-1); 
          break; 
        } 
        return true; 
       } 

       DateTime val; 
       if (!value.ParseDateTimeEx(CultureInfo.InvariantCulture, out val)) 
       { 
        return false; 
       } 

       if (val.Hour == 0 && val.Minute == 0) 
       { 
        // No hours and minutes specified, searching whole day or to the end of the day. 
        // If this is no range, we make it a range 
        result = new DateTime(val.Year, val.Month, val.Day); 
        switch (rangeType) 
        { 
         case RangeType.None: 
          result2 = ((DateTime)result).AddDays(1).AddMilliseconds(-1); 
          isRange = true; 
          break; 
         case RangeType.To: 
          result = ((DateTime)result).AddDays(1).AddMilliseconds(-1); 
          break; 
        } 
        return true; 
       } 

       result = val; 
       return true; 
      } 

      if (definedType == typeof(string)) 
      { 
       result = value; 
       return true; 
      } 

      return false; 
     } 

     public List<IPredicateItem> Items { get; private set; } 
    } 
} 

拡張\ StringExtensions.cs

using System; 
using System.Collections.Generic; 
using System.Globalization; 
using System.Linq; 

namespace LambdaSample.Extensions 
{ 
    public static class StringExtensions 
    { 
     private static List<string> GetValidDateTimeFormats() 
     { 
      var dateFormats = new[] 
      { 
       "dd.MM.yyyy", 
       "yyyy-MM-dd", 
       "yyyyMMdd", 
      }.ToList(); 
      var timeFormats = new[] 
      { 
       "HH:mm:ss.fff", 
       "HH:mm:ss", 
       "HH:mm", 
      }.ToList(); 

      var result = (from dateFormat in dateFormats 
          from timeFormat in timeFormats 
          select $"{dateFormat} {timeFormat}").ToList(); 

      return result; 
     } 

     public static bool ParseDateTimeEx(this string @this, CultureInfo culture, out DateTime dateTime) 
     { 
      if (culture == null) 
      { 
       culture = CultureInfo.InvariantCulture; 
      } 

      if (DateTime.TryParse(@this, culture, DateTimeStyles.None, out dateTime)) 
       return true; 

      var dateTimeFormats = GetValidDateTimeFormats(); 

      if (DateTime.TryParseExact(@this, dateTimeFormats.ToArray(), culture, DateTimeStyles.None, out dateTime)) 
       return true; 

      return false; 
     } 
    } 
} 

拡張子\ ObjectExtensions。CS

using System.Collections; 
using System.Collections.Generic; 
using System.Globalization; 
using System.Text; 

namespace LambdaSample.Extensions 
{ 
    public static class ObjectExtensions 
    { 
     /// <summary> 
     /// Build Filter Dictionary<string,string> used in ExpressionExtensions.BuildPredicate to build 
     /// predicates for Predicate Builder based on class's properties values. Filters are then used 
     /// by PredicateParser, which converts them to appropriate types (DateTime, int, decimal, etc.) 
     /// </summary> 
     /// <param name="this">Object to build dictionary from</param> 
     /// <param name="includeNullValues">Includes null values in dictionary</param> 
     /// <returns>Dictionary with string keys and string values</returns> 
     public static Dictionary<string, string> ToFilterDictionary(this object @this, bool includeNullValues) 
     { 
      var result = new Dictionary<string, string>(); 
      if (@this == null || [email protected]().IsClass) 
       return result; 

      // First, generate Dictionary<string, string> from @this by using reflection 
      var props = @this.GetType().GetProperties(); 
      foreach (var prop in props) 
      { 
       var value = prop.GetValue(@this); 
       if (value == null && !includeNullValues) 
        continue; 

       // If value already is a dictionary add items from this dictionary 
       var dictValue = value as IDictionary; 
       if (dictValue != null) 
       { 
        foreach (var key in dictValue.Keys) 
        { 
         var valueTemp = dictValue[key]; 
         if (valueTemp == null && !includeNullValues) 
          continue; 
         result.Add(key.ToString(), valueTemp != null ? valueTemp.ToString() : null); 
        } 
        continue; 
       } 

       // If property ends with list, check if list of generics 
       if (prop.Name.EndsWith("List", false, CultureInfo.InvariantCulture)) 
       { 
        var propName = prop.Name.Remove(prop.Name.Length - 4, 4); 
        var sb = new StringBuilder(); 
        var list = value as IEnumerable; 
        if (list != null) 
        { 
         foreach (var item in list) 
         { 
          if (item == null) 
           continue; 
          if (sb.Length > 0) 
           sb.Append(","); 
          sb.Append(item.ToString()); 
         } 
         result.Add(propName, sb.ToString()); 
        } 
        continue; 
       } 

       var str = value != null ? value.ToString() : null; 
       result.Add(prop.Name, str); 
      } 

      return result; 
     } 
    } 
} 

拡張\ ExpressionExtensions.cs

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Reflection; 
using LambdaSample.Framework; 
using LambdaSample.Interfaces; 
using LinqKit; 

namespace LambdaSample.Extensions 
{ 
    public static class ExpressionExtensions 
    { 
     private static readonly MethodInfo StringContainsMethod = typeof(string).GetMethod(@"Contains", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null); 
     private static readonly MethodInfo StringStartsWithMethod = typeof(string).GetMethod(@"StartsWith", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null); 
     private static readonly MethodInfo StringEndsWithMethod = typeof(string).GetMethod(@"EndsWith", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string) }, null); 
     private static readonly MethodInfo ObjectEquals = typeof(object).GetMethod(@"Equals", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(object) }, null); 
     //private static readonly MethodInfo BooleanEqualsMethod = typeof(bool).GetMethod(@"Equals", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(bool) }, null); 

     /// <summary> 
     /// Build a predicate with linq clauses, taking searchCriteria object's properties to define where conditions. 
     /// </summary> 
     /// <typeparam name="TDbType">Type of entity to build predicate for</typeparam> 
     /// <param name="searchCriteria">Object which contains criteria for predicate</param> 
     /// <param name="predicateParser">Implementation of predicate parser that will parse predicates as string</param> 
     /// <param name="includeNullValues">Determines whether null values are included when constructing query</param> 
     /// <returns></returns> 
     public static Expression<Func<TDbType, bool>> BuildPredicate<TDbType>(object searchCriteria, IPredicateParser predicateParser, bool includeNullValues) 
     { 
      var filterDictionary = searchCriteria.ToFilterDictionary(includeNullValues); 
      return BuildPredicate<TDbType>(filterDictionary, predicateParser); 
     } 

     public static Expression<Func<TDbType, bool>> BuildPredicate<TDbType>(Dictionary<string, string> searchCriteria, IPredicateParser predicateParser) 
     { 
      var predicateOuter = PredicateBuilder.New<TDbType>(true); 
      var predicateErrorFields = new List<string>(); 

      var dict = searchCriteria;// as Dictionary<string, string>; 
      if (dict == null || !dict.Any()) 
       return predicateOuter; 

      var searchFields = typeof(TDbType).GetProperties(); 
      foreach (var searchField in searchFields) 
      { 
       // Get the name of the DB field, which may not be the same as the property name. 
       var dbFieldName = GetDbFieldName(searchField); 

       var dbType = typeof(TDbType); 

       var dbFieldMemberInfo = dbType.GetMember(dbFieldName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance).SingleOrDefault(); 
       if (dbFieldMemberInfo == null || !dict.ContainsKey(dbFieldMemberInfo.Name)) 
        continue; 

       var predicateValue = dict[dbFieldMemberInfo.Name]; 
       if (predicateValue == null) 
        continue; 

       var rangesAllowed = searchField.PropertyType != typeof(string); 
       if (!predicateParser.Parse(predicateValue, rangesAllowed, searchField.PropertyType)) 
       { 
        predicateErrorFields.Add(dbFieldMemberInfo.Name); 
        continue; 
       } 
       if (!predicateParser.Items.Any()) 
        continue; 

       var predicateInner = BuildInnerPredicate<TDbType>(predicateParser, searchField, dbFieldMemberInfo); 
       if (predicateInner == null) 
        continue; 

       predicateOuter = predicateOuter.And(predicateInner); 
      } 

      return predicateOuter; 
     } 

     private static Expression<Func<TDbType, bool>> BuildInnerPredicate<TDbType>(IPredicateParser predicateParser, PropertyInfo searchField, MemberInfo dbFieldMemberInfo) 
     { 
      var dbType = typeof(TDbType); 

      // Create an "x" as TDbType 
      var dbTypeParameter = Expression.Parameter(dbType, @"x"); 

      // Get at x.firstName 
      var dbFieldMember = Expression.MakeMemberAccess(dbTypeParameter, dbFieldMemberInfo); 

      Expression<Func<TDbType, bool>> predicateInner = null; 

      foreach (var predicateItem in predicateParser.Items) 
      { 
       var predicateItemSingle = predicateItem as PredicateItemSingle; 
       var predicateItemRange = predicateItem as PredicateItemRange; 

       if (predicateItemSingle != null) 
       { 
        // Create the MethodCallExpression like x.firstName.Contains(criterion) 
        if (searchField.PropertyType == typeof(string)) 
        { 
         var str = predicateItemSingle.Value as string ?? ""; 
         var startsWithAsterisk = str.StartsWith("*"); 
         var endsWithAsterisk = str.EndsWith("*"); 
         str = str.Trim('*').Trim(); 

         MethodCallExpression callExpression; 
         if (startsWithAsterisk && !endsWithAsterisk) 
         { 
          callExpression = Expression.Call(dbFieldMember, StringEndsWithMethod, new Expression[] { Expression.Constant(str) }); 
         } 
         else if (!startsWithAsterisk && endsWithAsterisk) 
         { 
          callExpression = Expression.Call(dbFieldMember, StringStartsWithMethod, new Expression[] { Expression.Constant(str) }); 
         } 
         else 
         { 
          callExpression = Expression.Call(dbFieldMember, StringContainsMethod, new Expression[] { Expression.Constant(str) }); 
         } 
         predicateInner = (predicateInner ?? PredicateBuilder.New<TDbType>(false)).Or(Expression.Lambda(callExpression, dbTypeParameter) as Expression<Func<TDbType, bool>>); 
        } 
        else 
        { 
         if (dbFieldMember.Type.IsEnum) 
         { 
          if (!dbFieldMember.Type.IsEnumDefined(predicateItemSingle.Value)) 
           continue; 

          var enumValue = (int)predicateItemSingle.Value; 
          if (enumValue <= 0) 
           continue; 

          var enumObj = Enum.ToObject(dbFieldMember.Type, (int)predicateItemSingle.Value); 
          predicateInner = (predicateInner ?? PredicateBuilder.New<TDbType>(false)).Or(Expression.Lambda<Func<TDbType, bool>>(Expression.Equal(dbFieldMember, Expression.Constant(enumObj)), new[] { dbTypeParameter })); 
         } 
         else 
         { 
          predicateInner = (predicateInner ?? PredicateBuilder.New<TDbType>(false)).Or(Expression.Lambda<Func<TDbType, bool>>(Expression.Equal(dbFieldMember, Expression.Constant(predicateItemSingle.Value)), new[] { dbTypeParameter })); 
         } 
        } 
       } 
       else if (predicateItemRange != null) 
       { 
        var predicateRange = PredicateBuilder.New<TDbType>(true); 
        predicateRange = predicateRange.And(Expression.Lambda<Func<TDbType, bool>>(Expression.GreaterThanOrEqual(dbFieldMember, Expression.Constant(predicateItemRange.Value1)), new[] { dbTypeParameter })); 
        predicateRange = predicateRange.And(Expression.Lambda<Func<TDbType, bool>>(Expression.LessThanOrEqual(dbFieldMember, Expression.Constant(predicateItemRange.Value2)), new[] { dbTypeParameter })); 
        predicateInner = (predicateInner ?? PredicateBuilder.New<TDbType>(false)).Or(predicateRange); 
       } 
      } 

      return predicateInner; 
     } 

     private static string GetDbFieldName(PropertyInfo propertyInfo) 
     { 
      var dbFieldName = propertyInfo.Name; 
      // TODO: Can put custom logic here, to obtain another field name if desired. 
      return dbFieldName; 
     } 
    } 
} 

使用

我々はHOL DbPersonクラスがあるとしましょう我々のデータのds:

public class DbPersonFilter 
{ 
    public string Id { get; set; } 

    public string FirstName { get; set; } 

    public string LastName { get; set; } 

    public string BirthDate { get; set; } 

    public string Age { get; set; } 
} 

お知らせ基底クラスDbPersonDbPersonFilterのプロパティの名前がどのように:

public class DbPerson 
{ 
    public int Id { get; set; } 

    public string FirstName { get; set; } 

    public string LastName { get; set; } 

    public DateTime BirthDate { get; set; } 

    public int Age { get; set; } 
} 

そして、そのDbPersonクラスの横に、我々はDbPersonオブジェクトのための私達のフィルターを表すクラスを持っている

同じ。これは、上記のコードの多くが命名規則に一貫性があることを要求するため、重要です。ただし、プロパティのタイプは同じではありません。これは、フィルタの場合、1つの値だけでなく、検索する範囲を設定できるためです。後で、これがどのように動作するかを見るためのサンプルがいくつかあります。

ここで、「データベース」に簡単なデータを入力しましょう。私たちは、このメソッドを使用します。このサンプル・アプリケーションの句を使用して

private List<DbPerson> GenerateTestDb() 
{ 
    var result = new List<DbPerson> 
    { 
     new DbPerson { Id = 1,FirstName = "John", LastName = "Doe", BirthDate = new DateTime(1963, 6, 14), Age = 53 }, 
     new DbPerson { Id = 2,FirstName = "Jane", LastName = "Hunt", BirthDate = new DateTime(1972, 1, 16), Age = 44 }, 
     new DbPerson { Id = 3,FirstName = "Aaron", LastName = "Pitch", BirthDate = new DateTime(1966, 7, 31), Age = 50 }, 
    }; 

    return result; 
} 

は次のとおりです。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Windows.Forms; 
using LambdaSample.Extensions; 
using LambdaSample.Framework; 
using LinqKit; 

、アプリであなたの本でしょうもちろん、私たちのWinFormsアプリケーション(、でいくつかのbtnTestをを作成することができます何でもよい):

private void btnTest_Click(object sender, EventArgs e) 
{ 
    // Load sample database into db (db is actually List<DbPerson>) 
    var db = GenerateTestDb(); 

    // Create filter looking for FirstName is "John" 
    var filterValues = new DbPersonFilter 
    { 
     FirstName = "John", 
    }; 

    // Build PredicateParser which it used to parse predicates inside ExpressionExtensions. 
    var predicateParser = new PredicateParser(); 

    // Build predicate... 
    var predicate1 = PredicateBuilder.New(ExpressionExtensions.BuildPredicate<DbPerson>(filterValues, predicateParser, true)); 
    // And search for items... 
    var items1 = db.AsQueryable().AsExpandable().Where(predicate1).ToList(); 

    // Create filter to look for items where Id is between 1 and 2 
    filterValues = new DbPersonFilter 
    { 
     Id = "1-2", 
    }; 
    // Build predicate... 
    var predicate2 = PredicateBuilder.New(ExpressionExtensions.BuildPredicate<DbPerson>(filterValues, predicateParser, true)); 
    // And search for items... 
    var items2 = db.AsQueryable().AsExpandable().Where(predicate2).ToList(); 

    // Create filter to look for items where Age is 44 
    filterValues = new DbPersonFilter 
    { 
     Age = "44", 
    }; 
    // Build predicate... 
    var predicate3 = PredicateBuilder.New(ExpressionExtensions.BuildPredicate<DbPerson>(filterValues, predicateParser, true)); 
    // And search for items... 
    var items3 = db.AsQueryable().AsExpandable().Where(predicate3).ToList(); 
} 

これは役立ちます。コメントはどこにも含まれていないので、コードは自明でなければなりません。これ以上質問がある場合は、質問してください。

注:.AsExpandable()があるとLinqKitの拡張メソッド、Where拡張メソッド内PredicateBuilderを使用します。

+0

それを通るのに私はしばらく時間をとったが、ありがとう。 =) – Pegu

+0

問題ありません。それが役に立てば幸い。 – Jure

関連する問題