2010-05-05 1 views
11

В моем родовом хранилище У меня есть ниже метод:Как сделать заказBy на общий IEnumerable (IEnumerable <T>) с помощью LINQ в C#?

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

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

Quote from ScottGu:

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

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

+0

Вы можете даже перегрузить этот метод, например GetAll (Func orderByClause) и использовать логику построителя выражений для генерации функции. Это что-то нецелесообразно для вашего дела? – Perpetualcoder

+0

@Perpetualcoder вы можете добавить ответ? Благодарю. Я думаю, вы имеете в виду нечто подобное этому? http://blogs.sftsrc.com/stuart/archive/2009/02/19/130.aspx – Jeff

+0

Посмотрите на [этот ответ] [1] Приветствия [1]: http://stackoverflow.com/a/12920596/1139347 – joaopintocruz

ответ

4

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

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

-1

это должно сделать трюк:

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

Я не думаю, что это сработает, так как мы не знали бы тип itm, следовательно нет .property будет разрешено. – Jeff

5

Вы не можете сделать это в общем, если не ограничить параметр типа 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 
{ 
} 
+0

Это означает, что мне нужно иметь все мои linq для классов sql, которые имеют SortOrder для реализации интерфейса IHaveTheProperty? – Jeff

+0

Другие вопросы: как я могу передать T, который реализует IHaveTheProperty? Поскольку GetAll является общим и используется по всем направлениям, поэтому некоторые типы T не будут иметь свойство SortOrder. Таким образом, похоже, что мне нужно иметь 2 метода GetAll (1 для SortOrder T типов 1 без), но этого я и стараюсь избегать. – Jeff

+0

Каждый раз, когда общий метод использует член класса, он должен быть ограничен набором типов, которые имеют этот элемент. Это можно сделать путем ограничения интерфейса или ограничения базового класса, но это необходимо сделать. Если у вас есть T с и некоторые без определенного члена, вам нужны два отдельных общих метода с разными ограничениями. –

5

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

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 уже очень легко получить все объекты из таблицы, и есть простой способ упорядочить эти объекты. Если вы научитесь правильно использовать предоставленные интерфейсы, ваши запросы также будут намного быстрее и будут использовать меньше памяти, потому что вы получите базу данных для фильтрации вместо вас, а не для фильтрации на клиенте.

7
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); 

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

0

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

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 делают опционные и сделать то же самое в одном методе , Вам понадобится построитель предикатов, такой как логика, чтобы помочь вашим клиентам создавать сборку делегатов «на лету». Ссылка Джеффри на мой комментарий kinda иллюстрирует все это! И это из расширенного материала от C# 3.0 в двух словах тоже круто! Если вам нужно быстро запустить код, он даже имеет это значение LinqKit