2

これが完全に可能かどうかはわかりません。式ビルダーと述語ビルダーに関するいくつかの情報を見つけましたが、これまでのところ、事前に知らなくても任意のクエリを実行できるものはありません。

基本的に、大規模な SQL データベースからのオブジェクトのコレクションがあり、ユーザーがこれらのオブジェクトを表示およびフィルターできるようにする Web ページ (ASP.NET MVC 4) を構築しています。ユーザーが入力するクエリの複雑さはさまざまです。これらのクエリを入力させる最も簡単で適切な方法は、Visual Studio TFS プラグインで作業項目を検索できるようにする方法のようなものです。行を追加し続けることができる条件のテーブルです。結合条件として「and」または「or」を選択し、フィールドを選択して値を入力し、それに一致するか一致しないかを選択します。

1. show items where [Field] [is|is not] [value]
2.         [and|or] [Field] [is|is not] [value]
3.         [and|or] [Field] [is|is not] [value]
etc...

.ToList()それを最後に貼り付けられるLINQ風に変える最も簡単な方法は何ですか? 私がこれまでに思いついた唯一の解決策は、さまざまなフィールドに一致.Where()して .このようなもの:

  • 条件が AND の間:
    • フィールドに合わせて大きなスイッチを使用する
    • query = query.Where(ThisField == value);
  • OR の条件に該当する場合:
    • 現在の結果を一時リストに追加
    • フィルタリングされていない完全なリストからの新しいクエリ
    • フィールドに合わせて大きなスイッチを使用する
    • query = fullList.Where(ThisField == value);
    • 今まで通り続ける
  • 条件がなくなったら、現在の結果セットをずっと使用してきた一時リストに追加し、そのリストを返します。

これは私が望むよりもエレガントではないようです。

4

4 に答える 4

8

あなたはこのようにそれを行うことができます:

class Program
{
    public enum Operator
    {
        And,
        Or
    }

    public class Condition
    {
        public Operator Operator { get; set; }
        public string FieldName { get; set; }
        public object Value { get; set; }
    }

    public class DatabaseRow
    {
        public int A { get; set; }
        public string B { get; set; }
    }

    static void Main(string[] args)
    {
        var conditions = new List<Condition>
        {
            new Condition { Operator = Operator.And, FieldName = "A", Value = 1 },
            new Condition { Operator = Operator.And, FieldName = "B", Value = "Asger" },
            new Condition { Operator = Operator.Or, FieldName = "A", Value = 2 },
        };

        var parameter = Expression.Parameter(typeof (DatabaseRow), "x");
        var currentExpr = MakeExpression(conditions.First(), parameter);
        foreach (var condition in conditions.Skip(1))
        {
            var nextExpr = MakeExpression(condition, parameter);
            switch (condition.Operator)
            {
                case Operator.And:
                    currentExpr = Expression.And(currentExpr, nextExpr);
                    break;
                case Operator.Or:
                    currentExpr = Expression.Or(currentExpr, nextExpr);
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }
        }

        var predicate = Expression.Lambda<Func<DatabaseRow, bool>>(currentExpr, parameter).Compile();

        var input = new[]
        {
            new DatabaseRow {A = 1, B = "Asger"},
            new DatabaseRow {A = 2, B = "Hans"},
            new DatabaseRow {A = 3, B = "Grethe"}
        };

        var results = input.Where(predicate).ToList();
    }

    static BinaryExpression MakeExpression(Condition condition, ParameterExpression parameter)
    {
        return Expression.Equal(
            Expression.MakeMemberAccess(parameter, typeof (DatabaseRow).GetMember(condition.FieldName)[0]),
            Expression.Constant(condition.Value));
    }
}

これは、正しいタイプのデータベース行のモデルとしてクラスがあることを前提としています。次に、条件を正規表現を介して上記の型付き条件のリストに解析し、提供されたコードでそれを式ツリーに変換できます。結果の式は、コンパイルして実行するか(図のように)、SQLに変換することができます(代わりに、述語をIQueryable.Whereに詰め込むだけです)。

于 2013-02-13T12:48:10.147 に答える
2

PredicateBuilderこれを行うには、LINQKitから使用できます。そのAnd()および拡張メソッドを使用して、クエリの式ツリーOr()を構築できます。次に、その式ツリーを の条件として使用できます。また、または作成した式を呼び出すか、呼び出す必要があります。Where()AsExpandable()queryExpand()

于 2013-02-13T11:28:57.950 に答える
0

Dynamic Linq を使用して、条件を動的に追加できます。

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspxを参照してください。

于 2013-02-12T15:27:31.027 に答える