Ctr*_*eat 3 c# linq linq-to-entities entity-framework dynamic-linq
我在ASP.NET MVC 3站点中的很多页面中使用数据表.他们使用服务器端分页,现在我想基于列标题实现排序.数据表带有iSortCol_0 哪个是单击列的int值.
我不喜欢这种方法,因为查询最终会像:
if(iSortCol_0 == 0)
{
// query
// OderBy(x => x.CarName)
}
Run Code Online (Sandbox Code Playgroud)
然后对每列重复这一过程(加上每个列的else子句按降序排序).所以我改变了我的方法,现在将列名传递给服务器.
我想出了以下内容:
Expression<Func<vw_Car, string>> sortExpression1 = null;
Expression<Func<vw_Car, int>> sortExpression2 = null;
switch(columnToSort)
{
case "InvoiceNo": sortExpression1 = x => x.CarNo; break;
case "ClientNumber": sortExpression1 = x => x.ForeName; break;
case "ClientName": sortExpression1 = x => x.SurName; break;
default: sortExpression2 = x => x.Age.Value; break;
}
// start of query
.OrderByDir(sortDirection, sortExpression1 , sortExpression2)
Run Code Online (Sandbox Code Playgroud)
现在OrderByDir看起来如下:
public static IOrderedQueryable<T> OrderByDir<T>(this IQueryable<T> source, string dir, Expression<Func<T, string>> column1, Expression<Func<T, int>> column2)
{
if (column1 != null)
{
return dir == "asc" ? source.OrderBy(column1) : source.OrderByDescending(column1);
}
if (column2 != null)
{
return dir == "asc" ? source.OrderBy(column2) : source.OrderByDescending(column2);
}
return null;
}
Run Code Online (Sandbox Code Playgroud)
这适用于它对类型string或类型的列进行排序int.我有另一列DateTime我想要排序,所以我需要写另一个sortExpression3,然后将其添加到我的OrderByDir.
但我真的不喜欢的实现-我曾试图写了一个对象作为第二个参数,而不是一个通用的排序表达式string,int,Datetime,但是当在地方有这个代码,我越来越无法投型"系统. DateTime'键入'System.Object'.LINQ to Entities仅支持转换实体数据模型基元类型.
任何一个关于可能更好的方法的想法?
此类扩展应符合您的需求:
public static class LinqExtensions
{
public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string property)
{
return ApplyOrder(source, property, "OrderBy");
}
public static IOrderedQueryable<T> OrderByDescending<T>(this IQueryable<T> source, string property)
{
return ApplyOrder(source, property, "OrderByDescending");
}
private static IOrderedQueryable<T> ApplyOrder<T>(IQueryable<T> source, string property, string methodName)
{
var props = property.Split('.');
var type = typeof(T);
var arg = Expression.Parameter(type, "x");
Expression expr = arg;
foreach (var prop in props)
{
// use reflection (not ComponentModel) to mirror LINQ
var pi = type.GetProperty(prop);
expr = Expression.Property(expr, pi);
type = pi.PropertyType;
}
var delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
var lambda = Expression.Lambda(delegateType, expr, arg);
var result = typeof(Queryable).GetMethods().Single(
method => method.Name == methodName
&& method.IsGenericMethodDefinition
&& method.GetGenericArguments().Length == 2
&& method.GetParameters().Length == 2)
.MakeGenericMethod(typeof(T), type)
.Invoke(null, new object[] { source, lambda });
return (IOrderedQueryable<T>)result;
}
}
Run Code Online (Sandbox Code Playgroud)
调用示例:
query.OrderBy("Age.Value");
Run Code Online (Sandbox Code Playgroud)