В моем универсальном репозитории я имею ниже метода:
public virtual IEnumerable GetAll() where T : class
{
using (var ctx = new DataContext())
{
var table = ctx.GetTable().ToList();
return table;
}
}
T является Linq к классу Sql, и я хочу смочь к OrderBy на особом свойстве (т.е. международный SortOrder). Скажите, имеет ли T имя свойства "Порядок сортировки", затем делают OrderBy на этом свойстве. Но я не уверен, как я могу достигнуть этого. Таким образом, мне нужно, некоторые помогают.Спасибо! Я чувствую, что динамические языки действительно сияют в выполнении этого вида заданий!
В то время как запись безопасных с точки зрения типов запросов является большой для большинства сценариев, существуют случаи, где Вы хотите, чтобы гибкость динамично создала запросы на лету
И это - точно проблема, с которой я сталкиваюсь, и я задаюсь вопросом, может ли этот linq динамический помощник быть превращен в официальную библиотеку.NET.
Вы можете использовать динамическую библиотеку Linq, которая позволит вам сконструировать OrderBy динамически: http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx
Лично я всегда заставляю свои хранилища возвращать IQueryable, тогда потребитель может сам создавать дополнительную фильтрацию, упорядочивание или проекции по мере необходимости.
Вы не можете сделать это в общем случае, если не ограничите тип параметр 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 создаются частично
. Это означает, что вы можете создать другую часть класса, чтобы заставить один из этих классов реализовать ваш интерфейс:
public partial class Address : IHaveTheProperty
{
}
это должно помочь:
myEnumeration.OrderBy( itm => itm.SortOrder )
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);
К сожалению, вы должны указать тип ключа. Если только вы не начнете возиться с выражениями.
Если бы меня попросили сделать это, я бы сделал что-то вроде этого:
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 сделать параметр необязательным и выполнить то же самое в одном методе. Вам понадобится логика типа predicate builder, чтобы помочь вашему клиентскому коду создавать делегаты на лету. Ссылка Джеффри на мой комментарий как бы иллюстрирует все эти вещи! И эта ссылка из расширенного материала из C#3.0 в двух словах - тоже круто! Если вам нужно быстро разобрать код, у них даже есть вот это LinqKit
Чтобы это работало, вам нужно определить ограничение. Например:
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 уже очень легко получить все объекты из таблицы, и есть простой способ упорядочить эти объекты. Если вы научитесь правильно использовать предоставленные интерфейсы, ваши запросы также будут намного быстрее и будут использовать меньше памяти, потому что вы заставите базу данных выполнять фильтрацию вместо фильтрации на клиенте.