0

LINQ to SQL を使用して単純な再利用可能な検索を作成しようとしています。

検索ボックスに入力された単語のリストを渡します。結果は、この基準に基づいてフィルタリングされます。

  private IQueryable<User> BasicNameSearch(IQueryable<User> usersToSearch, ICollection<string> individualWordsFromSearch)
  {
        return usersToSearch
            .Where(user => 
            individualWordsFromSearch.Contains(user.Forename.ToLower()) 
            || individualWordsFromSearch.Contains(user.Surname.ToLower()));
  }

ここで、別のデータソースでこの同じ検索機能が必要であり、検索を適用するフィールドを動的に選択したいと考えています。たとえば、Users の IQueryable の代わりに Cars の IQueryable を使用すると、名と姓の代わりに Make と Model から検索が行われます。基本的には、実行時に検索対象を動的に選択して検索ロジックを再利用することが目標です。

4

2 に答える 2

2

stringセレクターをまとめて 1 つの式にコンパイルする拡張メソッドを作成できます。

public static class CompileExpressions
{
    public static IQueryable<T> SearchTextFieldsOr<T>(this IQueryable<T> source,
        ICollection<string> wordsFromSearch, params Func<T, string>[] stringSelectors)
    {
        Expression<Func<T, bool>> compiledExpression = t => false;

        foreach (var filter in stringSelectors)
        {
            compiledExpression = compiledExpression.Or(t => wordsFromSearch.Contains(filter(t)));
        }

        var compiled = compiledExpression.Compile();

        return source.Where(t => compiled(t));
    }

    public static IQueryable<T> SearchTextFieldsAnd<T>(this IQueryable<T> source,
        ICollection<string> wordsFromSearch, params Func<T, string>[] stringSelectors)
    {
        foreach (var filter in stringSelectors)
        {
            source = source.Where(t => wordsFromSearch.Contains(filter(t)));
        }

        return source;
    }

    //Taken from http://www.albahari.com/nutshell/predicatebuilder.aspx
    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                Expression<Func<T, bool>> expr2)
    {
        var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
        return Expression.Lambda<Func<T, bool>>
              (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
    }
}

これがどのように使用されるかの例:

public class Entity
{
    public string Name { get; set; }
    public string Type { get; set; }
    public string Model { get; set; }
    public string Colour { get; set; }
}

class Program
{
    static void Main(string[] args)
    {
        var source = new[]{
            new Entity { Colour = "Red", Model = "New", Name="Super", Type="Filter"},
            new Entity { Colour = "Green", Model = "New", Name="Super", Type="Filter"},
            new Entity { Colour = "Green", Model = "New", Name="Super", Type="Filter"},
            new Entity { Colour = "Green", Model = "New", Name="Super", Type="Filter"},
            new Entity { Colour = "Green", Model = "New", Name="Super", Type="Filter"},
            new Entity { Colour = "Green", Model = "New", Name="Super", Type="Amazing"},
        };

        var filters = new[] {"Red", "Amazing" };

        var filteredOr = source
               .AsQueryable()
               .SearchTextFieldsOr(filters, t => t.Colour, t => t.Type)
               .ToList();

        //2 records found because we're filtering on "Colour" OR "Type"

        var filteredAnd = source
               .AsQueryable()
               .SearchTextFieldsAnd(filters, t => t.Colour, t => t.Type)
               .ToList();

         //1 record found because we're filtering on "Colour" AND "Type"

    }
}

stringセレクター引数のタイプは であるため、クエリに含めたいparams Func<T, string>[]数のセレクターを追加できます。string

于 2013-11-04T16:09:30.983 に答える
0

あなたの質問はこのスレッドのものと似ています(ただし、同じ質問ではありません)。

簡単に言えば、linq-to-sql リクエストを作成すると、入力した実際のコードに対応する System.Linq.Expression のみが構築されます。このコードは「プロバイダー」に渡され、SQL に変換されます (取得できます)。 Provider プロパティを持つ IQueryable にリクエストをキャストすることにより、このプロバイダーを使用できます)。

実際、要求したコードが「実行」されることはなく、実際には、Linq-to-objects 関数に渡すデリゲートのように IL にコンパイルされることさえありません。(これはSystem.Linq.Enumerable拡張メソッドを使用していますが、linq-to-sql は拡張メソッドを使用してSystem.Linq.Queryableいます)

したがって、linq 式を「手動で」作成し (内部で C# コンパイラにビルドさせるのではなく)、それらをプロバイダーに渡すこともできます。プロバイダーは、通常の方法で作成したかのように解析して実行します。

上記のスレッドの例を参照してください。

編集:または、コピーアンドペースト実行のサンプルを提供してくれたオリバーの回答を見ることもできます:)

于 2013-11-04T16:09:21.337 に答える