2

ASP.NETMVCで動的検索画面を作成しました。ビューにすべてのフィールドを表示する代わりに、ユーザーが検索するフィールドを選択できるように、リフレクションを介してエンティティからフィールド名を取得しました。

検索結果がコントローラーにポストバックされると、FieldNameとValueを含むFormCollectionを受け取ります。検索されているフィールドの数がわかりません。FormCollectionには、ユーザーが選択したフィールドのみが含まれています。

たとえば、データベースにクエリを実行するときに、そのフィールド名を取得してLINQステートメントに適用できるようにしたいと思います。

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    List<People> searchResults = new List<People>();

    foreach (string key in fieldValueDictionary.Keys)
    {
         searchResults.Add(entities.People.Where(p => p.<use the key string as the fieldName> == fieldValueDictionary[key]));
    }

    return searchResults;
}

「キー文字列をfieldNameとして使用する」場合、p => p.FirstName == fieldValueDictionary [key] where key="FirstName"のようになります。Lambda式ツリーを使用しようとして失敗しましたが、DynamicLINQで少し成功しました。他の唯一の選択肢は、次のようなことを行うことです。

public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
{
    IQueryable<People> results = entities.People;

    foreach (string key in fieldValueDictionary.Keys)
    {
         switch (k)
         {
             case "FirstName": results = results.Where(entities.People.Where(p => p.FirstName == k);
             case "LastName": results = results.Where(entities.People.Where(p => p.LastName == k);
             // Repeat for all 26 fields in table
         }
    }

    return results.ToList<People>();
}

更新:次の投稿を通じてラムダ式ツリーの調査を行いました:

ラムダ式を動的に作成+linq+ OrderByDescending

Expression.Lambda()のパラメーターの問題

LINQ:ラムダ式をパラメーターとして渡し、メソッドによって実行および返される

ラムダを取得して次のように出力するところまで到達しました: "p => p.FirstName"ですが、これをwhereで機能させることはできません。助言がありますか?私のコードは以下の通りです:

MemberInfo member = typeof(People).GetProperty("FirstName");
ParameterExpression cParam = Expression.Parameter(typeof(People), "p");    
Expression body = Expression.MakeMemberAccess(cParam, member);        

var lambda = Expression.Lambda(body, cParam);
4

3 に答える 3

8

さらに多くの試行錯誤と検索を行った後、同じ問題を扱っている別のSO投稿を誤って見つけました。

InvalidOperationException:タイプ'System.Linq.Queryable'のメソッド'Where'は、指定された引数と互換性がありません

これが機能する私の変更されたコードです:

        IQueryable query = entities.People;
        Type[] exprArgTypes = { query.ElementType };

        string propToWhere = "FirstName";            

        ParameterExpression p = Expression.Parameter(typeof(People), "p");
        MemberExpression member = Expression.PropertyOrField(p, propToWhere);
        LambdaExpression lambda = Expression.Lambda<Func<People, bool>>(Expression.Equal(member, Expression.Constant("Scott")), p);                            

        MethodCallExpression methodCall = Expression.Call(typeof(Queryable), "Where", exprArgTypes, query.Expression, lambda);

        IQueryable q = query.Provider.CreateQuery(methodCall);

うまくいけばかなり簡単な変更で、これをどのタイプでも機能させることができるはずです。

回答ありがとうございますAni&John Bowen

于 2010-08-12T16:15:45.133 に答える
5

PropertyInfoから値を取得しようとしましたか?

entities.People.Where(p => (p.GetType().GetProperty(key).GetValue(p, null) as string) == fieldValueDictionary[key])
于 2010-08-11T23:03:07.667 に答える
1
  public List<People> SearchPeople(Dictionary<string, string> fieldValueDictionary)
        {
            return !fieldValueDictionary.Any()
                   ? entities.People 
                   : entities.People.Where(p => fieldValueDictionary.All(kvp => PropertyStringEquals(p, kvp.Key, kvp.Value)))
                                    .ToList();
        }

  private bool PropertyStringEquals(object obj, string propertyName, string comparison)
        {
            var val = obj.GetType().GetProperty(propertyName).GetValue(obj, null);
            return val == null ? comparison == null : val.ToString() == comparison; ;
        }
于 2010-08-11T23:01:33.923 に答える