应无所住,而生其心
排名
1
文章
860
粉丝
112
评论
163
net core webapi post传递参数
庸人 : 确实坑哈,我也是下班好了好几次,发现后台传递对象是可以的,但...
百度编辑器自定义模板
庸人 : 我建议换个编辑器,因为现在百度富文本已经停止维护了,用tinymec...
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术

表达式树+反射扩展EF实现动态排序。List动态排序

6988人阅读 2019/10/23 9:22 总访问:5185647 评论:0 收藏:0 手机
分类: EF

我们在显示表格的时候经常会在点击表头的时候实现排序,当然很多前端的框架都实现了当前页的页面排序,直接配置一下就行了,但是我们

这里要说的是全表排序,也就是前台需要传递排序字段(根据什么排序)和排序方式(升序或者降序)。


我们最容易想到的做法就是使用判断来,根据排序字段来判断根据什么排序

  1. if (sort.ToLower() == "max")
  2. {
  3.     if (sortway == "asc")
  4.     {
  5.         query = query.OrderBy(a => a.Max);
  6.     }
  7.     else
  8.     {
  9.         query = query.OrderByDescending(a => a.Max);
  10.     }
  11. }
  12. if (sort.ToLower() == "min")
  13. {
  14.     if (sortway == "asc")
  15.     {
  16.         query = query.OrderBy(a => a.Min);
  17.     }
  18.     else
  19.     {
  20.         query = query.OrderByDescending(a => a.Min);
  21.     }
  22. }
  23. if (sort.ToLower() == "sum")
  24. {
  25.     if (sortway == "asc")
  26.     {
  27.         query = query.OrderBy(a => a.Min);
  28.     }
  29.     else
  30.     {
  31.         query = query.OrderByDescending(a => a.Min);
  32.     }
  33. }

但是这样判断就太多了,如果其他地方也要用排序重复代码就会很多


我们可以发现其实排序字段和里边的a=>a.Max,a=>a.Min右边都是一样的,如果我们可以动态的构建一个lamdba式就好了。

其实是可以的,我们使用表达式树Expression就可以了

如下所示我们就可以根据一个字符串动态生成了一个a=a.Max的lamdba,在稍微封装一下代码

  1. if (!string.IsNullOrEmpty(sort))
  2. {
  3.     var left = Expression.Parameter(typeof(ScoreViewModel), "a");
  4.     var body = Expression.Property(left, sort);
  5.     Expression<Func<ScoreViewModel, double?>> lamdba = Expression.Lambda<Func<ScoreViewModel, double?>>(body, left);=
  6.     if (sortway == "asc")
  7.     {
  8.         query = query.OrderBy(lamdba);
  9.     }
  10.     else
  11.     {
  12.         query = query.OrderByDescending(lamdba);
  13.     }
  14. }

这样就可以实现动态排序了


根据最低分排序

但是现在还有2个问题要解决

1:把动态排序通过扩展方法的方式把ef扩展一下,可以直接用在ef上面

    这个问题还是很好解决,写个扩展方法封装一下就好了

  1. public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string sort, string sortway) 
  2. {
  3.     if (!string.IsNullOrEmpty(sort))
  4.     {
  5.         var left = Expression.Parameter(typeof(TSource), "a");
  6.         var body = Expression.Property(left, sort);
  7.         Expression<Func<TSource, int?>> lamdba = Expression.Lambda<Func<TSource, int?>>(body, left);
  8.         if (sortway == "asc")
  9.         {
  10.             source = source.OrderBy(lamdba);
  11.         }
  12.         else
  13.         {
  14.             source = source.OrderByDescending(lamdba);
  15.         }
  16.     }
  17.     return source;
  18. }

使用的时候很简单在后面直接点出来就好


2:我们现在写的动态排序只支持int类型,如果是小数类型排序就会报错,比如根据平均分排序

 所以我们这里不能写死,写死就不灵活了。这里就需要动态的获取属性类型,可以巧妙的使用反射方法来中转,因为反射调用方法的时候可以传递类型参数


第一步:要拿到排序字段的类型

  1. //第一步要拿到排序字段的类型
  2. Type propertyType = typeof(TSource).GetProperty(sort).PropertyType;

第二步:可以把方法提出来写,比如提出来一个处理升序的方法

  1. /// <summary>
  2. /// 处理升序排序
  3. /// 通过一个方法中转实现类型的传递
  4. /// </summary>
  5. public static IQueryable<TSource> DealAsc<TSource, M>(IQueryable<TSource> query, string sort)
  6. {
  7.     var left = Expression.Parameter(typeof(TSource), "a");
  8.     var body = Expression.Property(left, sort);
  9.     Expression<Func<TSource, M>> lamdba = Expression.Lambda<Func<TSource, M>>(body, left);
  10.     query = query.OrderBy(lamdba);
  11.     return query;
  12. }

注意:在这里就可以使用两个泛型了,这样动态构建的lamdba的类型就可以动态的来了


第二步:调用方法

这里如果直接调用也是没有办法传递类型的,第一步获取的类型无法提供给泛型

所以我们需要通过反射来调用

  1. //第一步要拿到排序字段的类型
  2. Type propertyType = typeof(TSource).GetProperty(sort).PropertyType;
  3. //通过反射拿到方法
  4. var method = typeof(MyEFTools).GetMethod("DealAsc");
  5. //给反射拿到的方法提供泛型
  6. method = method.MakeGenericMethod(typeof(TSource), propertyType);
  7. //反射调用方法
  8. IQueryable<TSource> result = (IQueryable<TSource>)method.Invoke(nullnew object[] { query, sort });

这里最关键的一步就是

  1. //给反射拿到的方法提供泛型
  2. method = method.MakeGenericMethod(typeof(TSource), propertyType);

这样就可以巧妙的传递类型了


最后贴一点完整的代码:

  1. public static class MyEFTools
  2. {
  3.     public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> query, string sort, string sortway)
  4.     {
  5.         if (!string.IsNullOrEmpty(sort))
  6.         {
  7.             //第一步要拿到排序字段的类型
  8.             Type propertyType = typeof(TSource).GetProperty(sort).PropertyType;
  9.             //通过反射拿到方法
  10.             var method = typeof(MyEFTools).GetMethod(sortway == "asc" ? "DealAsc" : "DealDesc");
  11.             //给反射拿到的方法提供泛型
  12.             method = method.MakeGenericMethod(typeof(TSource), propertyType);
  13.             //反射调用方法
  14.             IQueryable<TSource> result = (IQueryable<TSource>)method.Invoke(nullnew object[] { query, sort });
  15.             return result;
  16.         }
  17.         return query;
  18.     }
  19.     /// <summary>
  20.     /// 处理升序排序
  21.     /// 通过一个方法中转实现类型的传递
  22.     /// </summary>
  23.     public static IQueryable<TSource> DealAsc<TSource, M>(IQueryable<TSource> query, string sort)
  24.     {
  25.         var left = Expression.Parameter(typeof(TSource), "a");
  26.         var body = Expression.Property(left, sort);
  27.         Expression<Func<TSource, M>> lamdba = Expression.Lambda<Func<TSource, M>>(body, left);
  28.         query = query.OrderBy(lamdba);
  29.         return query;
  30.     }
  31.     /// <summary>
  32.     /// 处理降序排序
  33.     /// 通过一个方法中转实现类型的传递
  34.     /// </summary>
  35.     public static IQueryable<TSource> DealDesc<TSource, M>(IQueryable<TSource> query, string sort)
  36.     {
  37.         var left = Expression.Parameter(typeof(TSource), "a");
  38.         var body = Expression.Property(left, sort);
  39.         Expression<Func<TSource, M>> lamdba = Expression.Lambda<Func<TSource, M>>(body, left);
  40.         query = query.OrderByDescending(lamdba);
  41.         return query;
  42.     }
  43. }

最后的最后,当然我们可以继续优化一下代码,因为生成lamdba的代码重复了,我可以提一个方法出来

  1. public static class MyEFTools
  2. {
  3.     public static IQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> query, string sort, string sortway)
  4.     {
  5.         if (!string.IsNullOrEmpty(sort))
  6.         {
  7.             //第一步要拿到排序字段的类型
  8.             Type propertyType = typeof(TSource).GetProperty(sort).PropertyType;
  9.             //通过反射拿到方法
  10.             var method = typeof(MyEFTools).GetMethod(sortway == "asc" ? "DealAsc" : "DealDesc");
  11.             //给反射拿到的方法提供泛型
  12.             method = method.MakeGenericMethod(typeof(TSource), propertyType);
  13.             //反射调用方法
  14.             IQueryable<TSource> result = (IQueryable<TSource>)method.Invoke(nullnew object[] { query, sort });
  15.             return result;
  16.         }
  17.         return query;
  18.     }
  19.     /// <summary>
  20.     /// 处理升序排序
  21.     /// 通过一个方法中转实现类型的传递
  22.     /// </summary>
  23.     public static IQueryable<TSource> DealAsc<TSource, M>(IQueryable<TSource> query, string sort)
  24.     {
  25.         return query.OrderBy(OrderLamdba<TSource, M>(query, sort));
  26.     }
  27.     /// <summary>
  28.     /// 处理降序排序
  29.     /// 通过一个方法中转实现类型的传递
  30.     /// </summary>
  31.     public static IQueryable<TSource> DealDesc<TSource, M>(IQueryable<TSource> query, string sort)
  32.     {
  33.         return query.OrderByDescending(OrderLamdba<TSource, M>(query, sort));
  34.     }
  35.     static Expression<Func<TSource, M>> OrderLamdba<TSource, M>(IQueryable<TSource> query, string sort)
  36.     {
  37.         var left = Expression.Parameter(typeof(TSource), "a");
  38.         var body = Expression.Property(left, sort);
  39.         Expression<Func<TSource, M>> lamdba = Expression.Lambda<Func<TSource, M>>(body, left);
  40.         return lamdba;
  41.     }
  42. }

还有那个三明运算符找处理方法的代码不想用判断也可以直接构建一个字符串,然后反射的时候忽略一下大小写

好了就说到这里了,现在扩展的这个排序方法可以不用纠结类型了,直接传递排序字段和排序方式即可!



欢迎加群讨论技术,1群:677373950(满了,可以加,但通过不了),2群:656732739。有需要软件开发,或者学习软件技术的朋友可以和我联系~(Q:815170684)

评价

NET Core 使用 EF Code First

下面这些内容很老了看这篇:https://www.tnblog.net/aojiancc2/article/details/5365 项目使用多层,把数据库访问...

C out、rEF关键字的用法和区别

说说自己对out、ref的认识,面试问到的几率很高哟。out:classProgram { /* *out、ref都是引用传递,传递后使用都会改变...

Net Core使用EF之DB First

一.新建一个.net core的MVC项目新建好项目后,不能像以前一样直接在新建项中添加ef了,需要用命令在添加ef的依赖二.使用Nug...

EF6动态添加条件

例如我们要匹配一个集合中的所有关键字,我们首先想到的做法是这样的publicList&lt;Article&gt;GetArtByKeys(List&lt;strin...

Net Core使用依赖注入来装载EF的上下文对象

妹子情人节快乐~.net core中用了不少的依赖注入,官方文档中也推荐使用。这样使用依赖注入来管理ef对象,还是比较科学,比如...

NET CORE配置EF连接字符串。windows验证的连接字符串配置

在appsettings.json中配置好连接字符串{&quot;ConnectionStrings&quot;:{ &quot;BloggingDatabase&quot;:&quot;Server=(lo...

使用REFit框架访问REST接口

改装是一个类型安全的REST开源库,是一套基于RESTful架构的.NET客户端实现,内部使用HttpClient类封装,可通过改装更加简单...

docker启动报错 No dEFault Boot2Docker ISO found locally downloading the latest

这是因为,启动时如果检测到没有 Boot2Docker,就会去下载,这个下载过程出现网络连接上的错误了,导致启动失败。可以去下...

扩展EF自动映射需要查询的字段(表达式树Expression),动态构建返回值

Entity Framework 动态构造select表达式比如我们需要返回某些字段会采用如下的写法但是发现每次都去写select如果字段很多不...

layer弹窗+EF引入独立页面进行操作

使用layer弹窗进行操作的时候我们可以使用type=2,来把一个独立的页面指向content内容例如我们有一个表格,点击添加后,我...

Entity Framework常用查询,EF joinEF多表联查,原生sql。EF 多表查询。AsNoTracking

直接执行sql语句//全表查询 List&lt;Users&gt;ulist=se.Database.SqlQuery&lt;Users&gt;(&quot;select*fromusers&quot;).T...

EF Code First常用命令

Enable-Migrations启用数据库迁移Enable-Migrations –EnableAutomaticMigrations 启动自动迁移Add-Migration Name(名字可...

EF Code First 多对多关系配置

Code First配置多对多关系,常规有两种方法例如我们有一张学生表,和一张课程表,学生和课程是一个多对多的关系方法1:单纯...

解决:基础提供程序在 Open 上失败,EF无法生成实体问题

在学校图书馆的电脑上安装VS2013和SQL R2后,调试项目报错:基础提供程序在 Open 上失败怀疑是数据库的问题,然后删除数据...

net core过滤器。net core过滤器中获取依赖注入对象。net core过滤器中使用依赖注入。ServicEFilter 

虽然对象都可以直接实例化得到。但是所有的对象依赖关系,都用DI容器去管理,这样后面想要更换对象的时候也非常方便,项目...

EF状态System.Data.EntityState的一点理解

System.Data.EntityState一共有五种状态分别是Added,Deleted,Modified,UnChanged,Detached下面给一个简单的解释System.Data...