AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理、职称管理、部门管理、角色管理、角色权限管理等模块。

Entity Framework提供的排序功能

再来回顾一下上篇文章,加载用户列表并进行排序数据库分页的代码:

var q = DB.Users.Include(u => u.Dept);

// 在用户名称中搜索
string searchText = ttbSearchMessage.Text.Trim();
if (!String.IsNullOrEmpty(searchText))
{
q = q.Where(u => u.Name.Contains(searchText) || u.ChineseName.Contains(searchText) || u.EnglishName.Contains(searchText));
} // 过滤启用状态
if (rblEnableStatus.SelectedValue != "all")
{
q = q.Where(u => u.Enabled == (rblEnableStatus.SelectedValue == "enabled" ? true : false));
} // 在查询添加之后,排序和分页之前获取总记录数
Grid1.RecordCount = q.Count(); // 排列
q = q.OrderBy(u => u.Name); // 数据库分页
q = q.Skip(Grid1.PageIndex * Grid1.PageSize).Take(Grid1.PageSize); Grid1.DataSource = q;
Grid1.DataBind();

让我们把关注点集中到排序代码上:

q = q.OrderBy(u => u.Name);

在FineUI实际应用中,我们一般是从表格的 SortField 中读取排序字段,显然EF提供的OrderBy无法接受字符串表示的排序字段。

手工创建Lamba表达式  

通过搜索发现了这个帖子:http://stackoverflow.com/questions/10072250/generic-funct-k-to-sort-collections-of-different-types/10074873

据此我们可以写出如下的代码:

public Expression<Func<T, To>> GetSortExpression<T, To>(String sortBy)
{
var param = Expression.Parameter(typeof(T), "x");
Expression expr = Expression.Property(param, sortBy);
return Expression.Lambda<Func<T, To>>(expr, param);
} protected IQueryable<T> Sort<T>(IQueryable<T> q, FineUI.Grid grid)
{
string sortField = grid.SortField; if (grid.SortDirection == "ASC")
{
q = q.OrderBy(GetSortExpression<T, object>(sortField));
}
else
{
q = q.OrderByDescending(GetSortExpression<T, object>(sortField));
} return q;
}

经过测试,我们发现这个方法不支持bool, int, DateTime, DateTime?类型的列排序。

经过扩展后的代码如下所示:

protected IQueryable<T> Sort<T>(IQueryable<T> q, FineUI.Grid grid)
{
string sortField = grid.SortField;
var propertyType = typeof(T).GetProperty(sortField).PropertyType; if (grid.SortDirection == "ASC")
{
if (propertyType == typeof(bool))
{
q = q.OrderBy(GetSortExpression<T, bool>(sortField));
}
else if (propertyType == typeof(int))
{
q = q.OrderBy(GetSortExpression<T, int>(sortField));
}
else if (propertyType == typeof(DateTime))
{
q = q.OrderBy(GetSortExpression<T, DateTime>(sortField));
}
else if (propertyType == typeof(DateTime?))
{
q = q.OrderBy(GetSortExpression<T, DateTime?>(sortField));
}
else
{
q = q.OrderBy(GetSortExpression<T, object>(sortField));
}
}
else
{
if (propertyType == typeof(bool))
{
q = q.OrderByDescending(GetSortExpression<T, bool>(sortField));
}
else if (propertyType == typeof(int))
{
q = q.OrderByDescending(GetSortExpression<T, int>(sortField));
}
else if (propertyType == typeof(DateTime))
{
q = q.OrderByDescending(GetSortExpression<T, DateTime>(sortField));
}
else if (propertyType == typeof(DateTime?))
{
q = q.OrderByDescending(GetSortExpression<T, DateTime?>(sortField));
}
else
{
q = q.OrderByDescending(GetSortExpression<T, object>(sortField));
}
} return q;
}

但这种做法过于臃肿,有没有更好的办法呢?

更好的SortBy扩展方法  

后来,我们发现了这篇文章:http://stackoverflow.com/questions/3945645/sorting-gridview-with-entity-framework

通过对 IQueryable<T> 进行扩展,提供了接受类似 "Name DESC", "CreateTime", "CreateTime DESC" 参数的 SortBy 方法,更具有通用性。

原始的SortBy扩展方法:

public static class QueryExtensions {
public static IQueryable<T> SortBy<T>(this IQueryable<T> source, string propertyName) {
if (source == null) {
throw new ArgumentNullException("source");
}
// DataSource control passes the sort parameter with a direction
// if the direction is descending
int descIndex = propertyName.IndexOf(" DESC");
if (descIndex >= 0) {
propertyName = propertyName.Substring(0, descIndex).Trim();
} if (String.IsNullOrEmpty(propertyName)) {
return source;
} ParameterExpression parameter = Expression.Parameter(source.ElementType, String.Empty);
MemberExpression property = Expression.Property(parameter, propertyName);
LambdaExpression lambda = Expression.Lambda(property, parameter); string methodName = (descIndex < 0) ? "OrderBy" : "OrderByDescending"; Expression methodCallExpression = Expression.Call(typeof(Queryable), methodName,
new Type[] { source.ElementType, property.Type },
source.Expression, Expression.Quote(lambda)); return source.Provider.CreateQuery<T>(methodCallExpression);
}
}

不过这个方法不支持"Name ASC"形式的参数,所以我们进行了简单的修正,修正后的SortBy扩展方法:

public static class QueryExtensions
{
public static IQueryable<T> SortBy<T>(this IQueryable<T> source, string sortExpression)
{
if (source == null)
{
throw new ArgumentNullException("source");
} string sortDirection = String.Empty;
string propertyName = String.Empty; sortExpression = sortExpression.Trim();
int spaceIndex = sortExpression.Trim().IndexOf(" ");
if (spaceIndex < 0)
{
propertyName = sortExpression;
sortDirection = "ASC";
}
else
{
propertyName = sortExpression.Substring(0, spaceIndex);
sortDirection = sortExpression.Substring(spaceIndex + 1).Trim();
} if (String.IsNullOrEmpty(propertyName))
{
return source;
} ParameterExpression parameter = Expression.Parameter(source.ElementType, String.Empty);
MemberExpression property = Expression.Property(parameter, propertyName);
LambdaExpression lambda = Expression.Lambda(property, parameter); string methodName = (sortDirection == "ASC") ? "OrderBy" : "OrderByDescending"; Expression methodCallExpression = Expression.Call(typeof(Queryable), methodName,
new Type[] { source.ElementType, property.Type },
source.Expression, Expression.Quote(lambda)); return source.Provider.CreateQuery<T>(methodCallExpression);
} }

  

优化后的排序分页代码

首先在页面基类PageBase中定义排序和分页的代码(使用了前面定义的 SortBy 扩展函数):

protected IQueryable<T> Sort<T>(IQueryable<T> q, FineUI.Grid grid)
{
return q.SortBy(grid.SortField + " " + grid.SortDirection);
} protected IQueryable<T> SortAndPage<T>(IQueryable<T> q, FineUI.Grid grid)
{
return Sort(q, grid).Skip(grid.PageIndex * grid.PageSize).Take(grid.PageSize);
}

  

最终查询用户列表的代码:

var q = DB.Users.Include(u => u.Dept);

// 在用户名称中搜索
string searchText = ttbSearchMessage.Text.Trim();
if (!String.IsNullOrEmpty(searchText))
{
q = q.Where(u => u.Name.Contains(searchText) || u.ChineseName.Contains(searchText) || u.EnglishName.Contains(searchText));
} // 过滤启用状态
if (rblEnableStatus.SelectedValue != "all")
{
q = q.Where(u => u.Enabled == (rblEnableStatus.SelectedValue == "enabled" ? true : false));
} // 在查询添加之后,排序和分页之前获取总记录数
Grid1.RecordCount = q.Count(); // 排列和数据库分页
q = SortAndPage<User>(q, Grid1); Grid1.DataSource = q;
Grid1.DataBind();

  

下载或捐赠AppBox

1. AppBox v2.1 是免费软件,免费提供下载:http://fineui.com/bbs/forum.php?mod=viewthread&tid=3788

2. AppBox v3.0 是捐赠软件,你可以通过捐赠作者来获取AppBox v3.0的全部源代码(http://fineui.com/donate/)。

AppBox升级进行时 - 如何向OrderBy传递字符串参数(Entity Framework)的更多相关文章

  1. AppBox升级进行时 - 关联表查询与更新(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 关联表的查询操作 使用 Include 方法,我们可以在一次数据库查询中将关联 ...

  2. AppBox升级进行时 - Any与All的用法(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 属于某个角色的用户列表(Any的用法) 使用Subsonic,我们有两种方法获 ...

  3. AppBox升级进行时 - Entity Framework的增删改查

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Entity Framework新增数据 以新增用户为例,作为对比,先来看下使 ...

  4. AppBox升级进行时 - 拥抱Entity Framework的Code First开发模式

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 从Subsonic到Entity Framework Subsonic最早发布 ...

  5. AppBox升级进行时 - 扁平化的权限设计

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. AppBox v2.0中的权限实现 AppBox v2.0中权限管理中涉及三个 ...

  6. JS函数传递字符串参数(符号转义)

    原文链接:https://blog.csdn.net/Myname_China/article/details/82907965 JS函数传递字符串参数,如果没有转义处理,在接收的时候无法正确的接收字 ...

  7. vue中使用element组件时事件想要传递其他参数的问题

    在使用element的上传组件时在一下几个钩子中传递其他参数 图中是文件上传时的几个钩子,参数为文件或文件列表或者其他参数,但是现在我想在原有参数上传递其他参数.比如我想在on-success的钩子中 ...

  8. AppBox升级进行时 - Attach陷阱(Entity Framework)

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Attach方法 前面我们已经多次使用Attach方法,上一次使用Attach ...

  9. Oracle IN 传递字符串参数查询失效

    在写存储过程中有如下代码: FOR a IN ( SELECT a.svo_no,a.AUDIT_NO,a.order_id FROM TT_PI_MODEL_REL a ) LOOP SELECT ...

随机推荐

  1. 【单页应用之通信机制】view之间应该如何通信

    前言 在单页应用中,view与view之间的通信机制一直是一个重点,因为单页应用的所有操作以及状态管理全部发生在一个页面上 没有很好的组织的话很容易就乱了,就算表面上看起来没有问题,事实上会有各种隐忧 ...

  2. Mvc视图的那些事

    最近参与项目底层重写,在代码组织方式,类型使用上已经与之前有了很大的不同,这里总结一下视图的使用. 一.视图中命名空间的使用 视图命名空间的使用方式大致有三种:一,完全限定名,如 @System.Da ...

  3. [python]数据整理,将取得的众多的沪深龙虎榜数据整一整

    将昨日取得的众多的沪深龙虎榜数据整一整 提取文件夹内所有抓取下来的沪深龙虎榜数据,整理出沪深两市(含中小创)涨幅榜股票及前5大买入卖出资金净值,保存到csv文件 再手动使用数据透视表进行统计 原始数据 ...

  4. (转)TortoiseSVN与VisualSVN Server搭建SVN版本控制系统

    本片主要介绍如何搭建SVN版本控制系统,主要使用工具: 1 客户端:TortoiseSVN (小乌龟) 2 服务端:VisualSVN Server 搭建出图形化管理,以及右键菜单版本控制管理的SVN ...

  5. SharePoint 2013 Designer系列之数据视图筛选

    在SharePoint中,我们经常需要对列表进行简单的筛选,这时,数据视图就有作用了,我们可以定制对于字段的筛选,来进行展示:特别的,筛选不同于搜索,并没有对于附件或者文档的全文检索,如果需要全文检索 ...

  6. Thrift-java学习小结

    ➠更多技术干货请戳:听云博客 Thrift是什么?什么情况下使用thrift Thrift源于大名鼎鼎的facebook之手,在2007年facebook提交Apache基金会将Thrift作为一个开 ...

  7. MS SQL 错误:The operation could not be performed because OLE DB provider "SQLNCLI10" for linked server "test" was unable to begin a distributed transaction.

       一同事在测试服务器(系统:Windows 2008 R2 Standard 数据库:SQL SERVER 2008 R2)通过链接服务器test使用分布式事务测试时出错,出错信息如下: set ...

  8. There is insufficient system memory to run this query 错误

    服务器环境大致情况如下: 操作系统:   Microsoft Windows Server 2003 R2 Enterprise Edition Service Pack 2 数据库  :   Mic ...

  9. 浅谈Java中的Set、List、Map的区别(转)

    对JAVA的集合的理解是想对于数组: 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型),JAVA集合可以存储和操作数目不固定的一组数据. 所有的JAVA集合都位于 java ...

  10. 记录sql语句的执行记录,用于分析

    SET STATISTICS PROFILE ONSET STATISTICS IO ONSET STATISTICS TIME ONGO --这之间是要执行的脚本select * from [Use ...