Как сделать заказ на общий IEnumerable (IEnumerable <T>), используя LINQ в C #? - PullRequest
12 голосов
/ 05 мая 2010

В моем общем хранилище у меня есть метод ниже:

public virtual IEnumerable<T> GetAll<T>() where T : class
{
    using (var ctx = new DataContext())
    {
        var table = ctx.GetTable<T>().ToList();
        return table;
    }
}

T - это класс Linq to Sql, и я хочу иметь возможность OrderBy для определенного свойства (то есть int SortOrder). Скажем, если T имеет имя свойства "SortOrder", тогда выполните OrderBy для этого свойства. Но я не уверен, как мне этого добиться. Поэтому мне нужна помощь. Спасибо! Я чувствую, что динамические языки действительно сияют при выполнении такой работы!

Цитата из ScottGu :

При написании безопасных типов отлично подходит для большинства сценариев, есть случаи, когда вы хотите гибкость динамически строить запросы на муха

И это именно та проблема, с которой я сталкиваюсь, и мне интересно, можно ли превратить этот динамический помощник linq в официальную библиотеку .NET.

Ответы [ 6 ]

7 голосов
/ 05 мая 2010
public IEnumerable<T> GetAll<T,K>(Expression<Func<T,K>> sortExpr)
{
  using (var ctx = new DataContext())
  {
    ctx.ObjectTrackingEnabled = false;
    var table = ctx.GetTable<T>().OrderBy(sortExpr).ToList();
    return table;
  }
}

Использование:

var t = GetAll<Foo, int>(x => x.Bar);

К сожалению, вы должны указать тип ключа. Если только вы не начнете возиться с выражениями.

5 голосов
/ 05 мая 2010

Чтобы заставить это работать, вам нужно определить ограничение. Например:

public interface IOrderable
{
    int SortOrder { get; }
}

public virtual IEnumerable<T> GetAll<T>() where T : class, IOrderable
{
    ...
}

Теперь вы можете использовать ts.OrderBy(t => t.SortOrder) внутри тела метода. Все классы, которые вы намереваетесь использовать с этим методом, должны затем реализовать этот интерфейс.

Однако, как вы указали, классы LINQ To SQL не реализуют этот интерфейс. Я бы порекомендовал вам не использовать этот подход при использовании LINQ to SQL. С LINQ to SQL уже очень легко получить все объекты из таблицы, и есть простой способ упорядочить эти объекты. Если вы научитесь правильно использовать предоставленные интерфейсы, ваши запросы также будут выполняться намного быстрее и потреблять меньше памяти, потому что вы заставляете базу данных выполнять фильтрацию вместо вас на сервере.

5 голосов
/ 05 мая 2010

Вы не можете сделать это вообще, если вы не ограничите параметр типа T типом, у которого есть свойство, по которому вы хотите отсортировать. Например, если у вас есть интерфейс с именем IHaveTheProperty, вы можете сделать:

public virtual IEnumerable<T> GetAll<T>() where T : class, IHaveTheProperty
{
    using (var ctx = new DataContext())
    {
        ctx.ObjectTrackingEnabled = false;
        var table = ctx.GetTable<T>().ToList().AsReadOnly().OrderBy(t=>t.TheProperty);
        return table;
    }
}

Но без ограничений вы можете использовать только методы типа System.Object.


Созданы классы LINQ to SQL partial. Это означает, что вы можете создать другую часть класса, чтобы заставить один из этих классов реализовать ваш интерфейс:

public partial class Address : IHaveTheProperty
{
}
4 голосов
/ 05 мая 2010

Вы можете использовать динамическую библиотеку Linq, которая позволит вам динамически создавать OrderBy: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

Лично у меня всегда есть свои репозитории, которые возвращают IQueryable, тогда потребитель может справиться с созданием дополнительной фильтрации, упорядочивания или прогнозов по мере необходимости.

0 голосов
/ 05 мая 2010

Если бы меня попросили сделать это, я мог бы сделать что-то вроде этого:

public virtual IEnumerable<T> GetAll<T>() where T : class
{
    using (var ctx = new DataContext())
    {
        var table = ctx.GetTable<T>().ToList();
        return table;
    }
}

И

publuc virtual IEnumerable<T> GetAll<T>(Func<T,bool> orderByClause) where T:class{

return GetAll<T>().OrderBy(orderByClause);
}

или в .net 4 делают параметр необязательным и выполняют то же самое в одном методе. Вам понадобится построитель предикатов, такой как логика, чтобы помочь клиентскому коду создавать делегатов на лету. Ссылка Джеффри на мой комментарий как бы иллюстрирует все это! И эта ссылка из расширенного материала из C # 3.0 в двух словах тоже классная! Если вам нужно быстро запустить код, у них даже есть этот LinqKit

0 голосов
/ 05 мая 2010

это должно сработать:

myEnumeration.OrderBy( itm => itm.SortOrder )
...