AppBox升级进行时 - 如何向OrderBy传递字符串参数(Entity Framework)
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)的更多相关文章
- AppBox升级进行时 - 关联表查询与更新(Entity Framework)
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 关联表的查询操作 使用 Include 方法,我们可以在一次数据库查询中将关联 ...
- AppBox升级进行时 - Any与All的用法(Entity Framework)
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 属于某个角色的用户列表(Any的用法) 使用Subsonic,我们有两种方法获 ...
- AppBox升级进行时 - Entity Framework的增删改查
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Entity Framework新增数据 以新增用户为例,作为对比,先来看下使 ...
- AppBox升级进行时 - 拥抱Entity Framework的Code First开发模式
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 从Subsonic到Entity Framework Subsonic最早发布 ...
- AppBox升级进行时 - 扁平化的权限设计
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. AppBox v2.0中的权限实现 AppBox v2.0中权限管理中涉及三个 ...
- JS函数传递字符串参数(符号转义)
原文链接:https://blog.csdn.net/Myname_China/article/details/82907965 JS函数传递字符串参数,如果没有转义处理,在接收的时候无法正确的接收字 ...
- vue中使用element组件时事件想要传递其他参数的问题
在使用element的上传组件时在一下几个钩子中传递其他参数 图中是文件上传时的几个钩子,参数为文件或文件列表或者其他参数,但是现在我想在原有参数上传递其他参数.比如我想在on-success的钩子中 ...
- AppBox升级进行时 - Attach陷阱(Entity Framework)
AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. Attach方法 前面我们已经多次使用Attach方法,上一次使用Attach ...
- Oracle IN 传递字符串参数查询失效
在写存储过程中有如下代码: FOR a IN ( SELECT a.svo_no,a.AUDIT_NO,a.order_id FROM TT_PI_MODEL_REL a ) LOOP SELECT ...
随机推荐
- CSS3中flexbox如何实现水平垂直居中和三列等高布局
最近这些天都在弥补css以及css3的基础知识,在打开网页的时候,发现了火狐默认首页上有这样一个东西.
- li进度条宽度和颜色按顺序显示的效果。
实际项目中li和里边的数值是动态生成的,需要控制它的宽度和颜色,效果如图: 如果能实现颜色按数值规律变化就好了,目前颜色是固定到数组中的. 实例代码如下: <!DOCTYPE html>& ...
- iOS之2016面试题一
序言 招聘高峰期来了,大家都非常积极地准备着跳槽,那么去一家公司面试就会有一堆新鲜的问题,可能不会,也可能会,但是了解不够深.本篇文章为群里的小伙伴们去宝库公司的笔试题,由笔者整理并提供笔者个人参考答 ...
- Mou常用快捷键
title: Mou常用快捷键date: 2015-11-08 17:16:38categories: 编辑工具 tags: mou 小小程序猿我的博客:http://daycoding.com Vi ...
- IOS开发基础知识--碎片23
1:关于UITableView中关于行重复加载的问题 在Cell里重写prepareForReuse,对一些控件进行清空: 比较简单: -(void)prepareForReuse{ [super p ...
- 让我们来谈谈JDBC
1.JDBC 1)JDBC简介 - JDBC就是Java中连接数据库方式 - 我们可以通过JDBC来执行SQL语句. 2)获取数据库连接 - j ...
- SQL闲杂知识点汇总【2015年12月】
2015.12.14 知识点1:DEFAULT VALUES实现插入行 --临时创建临时表 CREATE TABLE [dbo].[tblTmp] ( iTmpID ,) NOT NULL PRIMA ...
- MySQL有关Group By的优化
昨天我写了有关MySQL的loose index scan的相关博文(http://www.cnblogs.com/wingsless/p/5037625.html),后来我发现上次提到的那个优化方法 ...
- Android 手势操作识别
(转自:http://jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/1020/448.html) 首先,在Android系统中,每一次手势交互都会依照 ...
- 报表移动端app如何实现页面自适应?
1. 描述 PC上制作好的报表,在手机端查看的时候,报表软件默认的自适应效果不尽人如意.例如,报表比较大,到手机上被缩的非常小,字都看不清等等.为此FineReport增加了选项可以手动控制报表在移动 ...