12

OrderByエンティティの列名を文字列として入力するラムダ式を使用してLINQ句を生成しようとしています(以下の「sortOn」変数内)。

以下のコードは、ラムダを生成する「コード」のような sortOn 値に対して正常に機能します

p => p.Code

しかし、ラムダが存在する可能性のある子エンティティもソートしたいと思います

p => p.Category.Description

したがって、この例では、sortOn = "Category.Description" を設定して、正しいラムバ式を生成したいと思います。

これは可能ですか?これを行うための最良の方法についての提案は歓迎されます。

このコードは、単純なケースでは問題なく機能します。

var param = Expression.Parameter(typeof (Product), "p");

var sortExpression = Expression.Lambda<Func<Product, object>>(
    Expression.Property(param, sortOn), param);

if (sortAscending ?? true)
{
   products = products.OrderBy(sortExpression);
}
else
{
   products = products.OrderByDescending(sortExpression);
}

この問題の使用例は、データのグリッドを表示し、並べ替える列名をサーバーに戻すだけでデータを並べ替えることができることです。ソリューションを一般的なものにしたいのですが、今のところ特定のタイプ (例では Product) の使用を開始しています。

4

5 に答える 5

19

これにより、適切なラムダ式が生成されます。

var sortOn = "Category.Description";
var param = Expression.Parameter(typeof(Product), "p");
var parts = sortOn.Split('.');

Expression parent = param;

foreach (var part in parts)
{
    parent = Expression.Property(parent, part);
}

var sortExpression = Expression.Lambda<Func<Product, object>>(parent, param);
于 2012-07-13T17:10:31.230 に答える
2

ダイナミック LINQ クエリ ライブラリを使用すると、これを簡単に行うことができます。IQueryable<T>の実装があると仮定するとProduct、簡単に実行できます。

IQueryable<Product> products = ...;

// Order by dynamically.
products = products.OrderBy("Category.Description");

ブログ投稿には libary へのリンクがあり、ソリューションにプロジェクトを自分でビルド/含める必要がありますが、非常にうまく機能し、解析は非常に堅牢です。これにより、解析コードを自分で作成する必要がなくなります。非常に単純なものであっても、要件が拡大すると、ライブラリがカバーしますが、自家製のソリューションはカバーしません。

また、他にも多数の動的演算子 ( SelectWhereなど) があるため、他の動的操作を実行できます。

内部に魔法はありません。渡された文字列を解析し、解析結果に基づいてラムダ式を作成するだけです。

于 2012-07-13T17:28:36.810 に答える
0

式が必要ない場合は、次のようにします。

products = products.Orderby(p1 => p1.Code).ThenBy(p2 => p2.Category.Description)
于 2012-07-13T17:01:56.170 に答える
0

こんにちは、子だけでなく任意の深さにソートできるような拡張メソッドを作成することもできます

        public static IEnumerable<TSource> CustomOrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
    {
        List<string> list=new List<string>();
        List<TSource> returnList=new List<TSource>();
        List<int> indexList = new List<int>();

        if (source == null)
            return null;
        if (source.Count() <= 0)
            return source;
        source.ToList().ForEach(sc=>list.Add(keySelector(sc).ToString())); //Extract the strings of property to be ordered

        list.Sort(); //sort the list of strings

        foreach (string l in list) // extract the list of indexes of source according to the order
        {
            int i=0;
            //list.ForEach(l =>

                foreach (var s in source.ToList())
                {
                    if (keySelector(s).ToString() == l)
                        break;
                    i++;
                }
                indexList.Add(i);
        }
        indexList.ForEach(i=>returnList.Add(source.ElementAt(i))); //rearrange the source according to the above extracted indexes
        return returnList;
    }
}
public class Name
{
    public string FName { get; set; }
    public string LName { get; set; }
}
public class Category
{
    public Name Name { get; set; }
}
public class SortChild
{
    public void SortOn()
    {
        List<Category> category = new List<Category>{new Category(){Name=new Name(){FName="sahil",LName="chauhan"}},
            new Category(){Name=new Name(){FName="pankaj",LName="chauhan"}},
            new Category(){Name=new Name(){FName="harish",LName="thakur"}},
            new Category(){Name=new Name(){FName="deepak",LName="bakseth"}},
            new Category(){Name=new Name(){FName="manish",LName="dhamaka"}},
            new Category(){Name=new Name(){FName="arev",LName="raghaka"}}
        };
        var a = category.CustomOrderBy(s => s.Name.FName);

    }

}

そのカスタム メソッドは現在、文字列プロパティに対してのみ機能しますが、ジェネリックを使用して反応させて、任意のプリミティブ型に対して機能させることができます。これが役立つことを願っています。

于 2012-07-13T18:09:52.357 に答える