所以我的问题是这样的;在C#代码中,我需要在Linq to Entities的帮助下执行实体集的多个排序,具体取决于输入参数。有三列要订购,订货列的顺序本身是可变的(这意味着对于每个订单,我需要查找要订购的列)。我怎样才能做到这一点?
我有一些应该可行的代码,但是由于我无法对我的操作进行参数化,所以我重复自己太多了(Linq to Entities是非常严格的。我可以在我的lambdas中做什么)。请建议我如何根据DRY原则重写我的代码,也许是在T4代码生成的帮助下?
以下代码应说明我的问题。这是真实代码的摘录,为简洁起见,请告诉我是否应该包含更多内容。 orderSpecs
变量是“订单规范”的数组,每个规范指定要订购的列以及是否以降序排序。 orderSpecs
数组至少有一个元素,因此至少执行一个排序。
using (var db = new MyContainer())
{
var orderSpec = orderSpecs[0];
IQueryable<DbVersion> dVersions = null;
if (orderSpec.Column == 0)
{
if (orderSpec.Descending)
{
dVersions = db.Versions.OrderByDescending(ver => ver.Name);
}
else
{
dVersions = db.Versions.OrderBy(ver => ver.Name);
}
}
else if (orderSpec.Column == 1)
{
if (orderSpec.Descending)
{
dVersions = db.Versions.OrderByDescending(ver => ver.Built);
}
else
{
dVersions = db.Versions.OrderBy(ver => ver.Built);
}
}
else if (orderSpec.Column == 2)
{
if (orderSpec.Descending)
{
dVersions = db.Versions.OrderByDescending(ver => ver.Id);
}
else
{
dVersions = db.Versions.OrderBy(ver => ver.Id);
}
}
foreach (var spec in orderSpecs.Skip(1))
{
if (spec.Column == 0)
{
if (spec.Descending)
{
dVersions = dVersions.ThenByDescending(ver => ver.Name);
}
else
{
dVersions = dVersions.ThenBy(ver => ver.Name);
}
}
else if (spec.Column == 1)
{
if (spec.Descending)
{
dVersions = dVersions.ThenByDescending(ver => ver.Built);
}
else
{
dVersions = dVersions.ThenBy(ver => ver.Built);
}
}
else if (spec.Column == 2)
{
if (spec.Descending)
{
dVersions = dVersions.ThenByDescending(ver => ver.Id);
}
else
{
dVersions = dVersions.ThenBy(ver => ver.Id);
}
}
}
答案 0 :(得分:13)
如何创建一个字典来映射这些导致这些巨大的if-else结构的列到属性。可能看起来像这样:
using (var db = new MyContainer())
{
var orderSpec = orderSpecs[0];
IQueryable<DbVersion> dVersions = null;
var mapping = new Dictionary<int, Func<DbVersion, object>>()
{
{ 0, ver => ver.Name },
{ 1, ver => ver.Built },
{ 2, ver => ver.Id }
};
if (orderSpec.Descending)
dVersions = db.Versions.OrderByDescending(mapping[orderSpec.Column]);
else
dVersions = db.Versions.OrderBy(mapping[orderSpec.Column]);
foreach (var spec in orderSpecs.Skip(1))
{
if (spec.Descending)
dVersions = dVersions.ThenByDescending(mapping[spec.Column]);
else
dVersions = dVersions.ThenBy(mapping[spec.Column]);
}
}
答案 1 :(得分:2)
对于 Untype :您还可以使用动态Linq库:Using the LINQ Dynamic Query Library
完整文章:Handle GridView.OnSorting() and create sorting expression dynamically using LINQ
对于键入:您可以执行动态排序,如下所示删除您编写的代码
如何在没有修改列名和排序方向的人员上打电话
IEnumerable<Person> persons = GetPersons();
persons = persons.OrderBy(e.SortExpression, e.SortDirection);
人类
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
带有用于排序数据的表达式树的通用方法
public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> collection,
string columnName, SortDirection direction)
{
ParameterExpression param = Expression.Parameter(typeof(T), "x"); // x
Expression property = Expression.Property(param, columnName); // x.ColumnName
Func<T, object> func = Expression.Lambda<Func<T, object>>( // x => x.ColumnName
Expression.Convert(Expression.Property(param, columnName),
typeof(object)), param).Compile();
Func<IEnumerable<T>, Func<T, object>, IEnumerable<T>> expression =
SortExpressionBuilder<T>.CreateExpression(direction);
IEnumerable<T> sorted = expression(collection, func);
return sorted;
}