web-dev-qa-db-ja.com

動的な文字列パラメーターでOrderByを実行するにはどうすればよいですか?

私はこれをやりたい:

var orderBy = "Nome, Cognome desc";

var timb = time.Timbratures.Include("Anagrafica_Dipendente")
    .Where(p => p.CodDipendente == 1);

if(orderBy != "")
    timb = timb.OrderBy(orderBy);

文字列パラメーターを受け入れるOrderByオーバーロードはありますか?

52
Luca Romagnoli

絶対に。 Scott Guthrieのブログ にあるLINQ Dynamic Query Libraryを使用できます。利用可能な更新バージョンもあります CodePlexで

文字列パラメーターを渡すことで、OrderBy句、Where句、その他すべてを作成できます。グリッドの並べ替え/フィルタリングなどの汎用コードを作成するのに最適です。

var result = data
    .Where(/* ... */)
    .Select(/* ... */)
    .OrderBy("Foo asc");

var query = DbContext.Data
    .Where(/* ... */)
    .Select(/* ... */)
    .OrderBy("Foo ascending");
41
Mike Mooney

プレーンなLINQ-to-objectsを使用していて、外部ライブラリに依存したくない場合は、目的を達成するのは難しくありません。

OrderBy()句は、ソース要素からソートキーを取得する_Func<TSource, TKey>_を受け入れます。 OrderBy()句の外側で関数を定義できます:

_Func<Item, Object> orderByFunc = null;
_

その後、ソート基準に応じて異なる値に割り当てることができます。

_if (sortOrder == SortOrder.SortByName)
  orderByFunc = item => item.Name;
else if (sortOrder == SortOrder.SortByRank)
  orderByFunc = item => item.Rank;
_

次に、ソートできます:

_var sortedItems = items.OrderBy(orderByFunc);
_

この例では、ソースタイプがItemおよびNameプロパティを持つRankであると想定しています。

この例では、TKeyObjectであり、ソート可能なプロパティタイプを制限しないことに注意してください。 funcが値型(_Int32_など)を返す場合、ソート時にボックス化されますが、これはやや非効率的です。 TKeyを特定の値型に制約できる場合、この問題を回避できます。

63

CodeConcussionの別のソリューション( https://stackoverflow.com/a/7265394/2793768

var param = "Address";    
var pi = typeof(Student).GetProperty(param);    
var orderByAddress = items.OrderBy(x => pi.GetValue(x, null));
29
Chinh Phan

これには外部ライブラリは必要ありません。以下のコードは、LINQ to SQL /エンティティに対して機能します。

    /// <summary>
    /// Sorts the elements of a sequence according to a key and the sort order.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of <paramref name="query" />.</typeparam>
    /// <param name="query">A sequence of values to order.</param>
    /// <param name="key">Name of the property of <see cref="TSource"/> by which to sort the elements.</param>
    /// <param name="ascending">True for ascending order, false for descending order.</param>
    /// <returns>An <see cref="T:System.Linq.IOrderedQueryable`1" /> whose elements are sorted according to a key and sort order.</returns>
    public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> query, string key, bool ascending = true)
    {
        if (string.IsNullOrWhiteSpace(key))
        {
            return query;
        }

        var lambda = (dynamic)CreateExpression(typeof(TSource), key);

        return ascending 
            ? Queryable.OrderBy(query, lambda) 
            : Queryable.OrderByDescending(query, lambda);
    }

    private static LambdaExpression CreateExpression(Type type, string propertyName)
    {
        var param = Expression.Parameter(type, "x");

        Expression body = param;
        foreach (var member in propertyName.Split('.'))
        {
            body = Expression.PropertyOrField(body, member);
        }

        return Expression.Lambda(body, param);
    }

CreateExpressionのコピー元 https://stackoverflow.com/a/16208620/111438

14
niaher

最もシンプルで最適なソリューション:

mylist.OrderBy(s => s.GetType().GetProperty("PropertyName").GetValue(s));
8
Kasper Roma

このブログをご覧ください こちらEntitySorter<T>を定義することにより、これを行う方法を説明します。

IEntitySorter<T>をサービスメソッドに渡し、次のように使用できます。

public static Person[] GetAllPersons(IEntitySorter<Person> sorter)
{
    using (var db = ContextFactory.CreateContext())
    {
        IOrderedQueryable<Person> sortedList = sorter.Sort(db.Persons);

        return sortedList.ToArray();
    }
}

そして、次のようなEntitiySorterを作成できます:

IEntitySorter<Person> sorter = EntitySorter<Person>
    .OrderBy(p => p.Name)
    .ThenByDescending(p => p.Id);

またはこのように:

var sorter = EntitySorter<Person>
     .OrderByDescending("Address.City")
     .ThenBy("Id");
6
Steven

私はそうしました:

using System.Linq.Expressions;

namespace System.Linq
{
    public static class LinqExtensions
    {

        public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string field, string dir = "asc")
        {
            // parametro => expressão
            var parametro = Expression.Parameter(typeof(TSource), "r");
            var expressao = Expression.Property(parametro, field);
            var lambda = Expression.Lambda(expressao, parametro); // r => r.AlgumaCoisa
            var tipo = typeof(TSource).GetProperty(field).PropertyType;

            var nome = "OrderBy";
            if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase))
            {
                nome = "OrderByDescending";
            }
            var metodo = typeof(Queryable).GetMethods().First(m => m.Name == nome && m.GetParameters().Length == 2);
            var metodoGenerico = metodo.MakeGenericMethod(new[] { typeof(TSource), tipo });
            return metodoGenerico.Invoke(source, new object[] { source, lambda }) as IOrderedQueryable<TSource>;

        }

        public static IOrderedQueryable<TSource> ThenBy<TSource>(this IOrderedQueryable<TSource> source, string field, string dir = "asc")
        {
            var parametro = Expression.Parameter(typeof(TSource), "r");
            var expressao = Expression.Property(parametro, field);
            var lambda = Expression.Lambda<Func<TSource, string>>(expressao, parametro); // r => r.AlgumaCoisa
            var tipo = typeof(TSource).GetProperty(field).PropertyType;

            var nome = "ThenBy";
            if (string.Equals(dir, "desc", StringComparison.InvariantCultureIgnoreCase))
            {
                nome = "ThenByDescending";
            }

            var metodo = typeof(Queryable).GetMethods().First(m => m.Name == nome && m.GetParameters().Length == 2);
            var metodoGenerico = metodo.MakeGenericMethod(new[] { typeof(TSource), tipo });
            return metodoGenerico.Invoke(source, new object[] { source, lambda }) as IOrderedQueryable<TSource>;
        }

    }
}

つかいます :

example.OrderBy("Nome", "desc").ThenBy("other")

次のように動作します:

example.OrderByDescending(r => r.Nome).ThenBy(r => r.other)

実行時にパラメーターを渡すには、LINQ 動的 クエリライブラリを使用する必要があります。

これにより、次のようなlinqステートメントが許可されます。

string orderedBy = "Description";
var query = (from p in products
            orderby(orderedBy)
            select p);
4
Nicholas Murray