使用Expression实现数据的任意字段过滤(2)
上一篇《使用Expression实现数据的任意字段过滤(1)》, 我们实现了通过CriteriaCollectionHandler对象来处理集合数据过滤。通过适当的扩展, 应该可以满足一般的筛选条件应用了。但是在我经历的项目中, 突然有个情况让我措手不及。下面和大家分享下。
这个项目叫WebAD,顾名思义, 就是将AD的管理界面使用Web来实现。 无可避免的要查询AD里面的对象,比如UserPrinciple,即查找某一OU节点下的所有用户。
先感受下UserPrinciple的属性
再感受下用户的气场:
“我需要用户的邮箱、部门名称、公司名称、密码修改时间…..”
好吧, 这些AD里有, UserPrincipal没有,但通过非公开的ExtensionGet()方法,这些变成可以有。
用户的气场再爆发:“我们还需要按邮箱名称、部门名称、公司名称来过滤!”
OMG,这合理,但,真的要这么做吗?
如果用传统的办法, 只能是按下面的步骤:
1) 从AD按OU节点查得所有的UserPrinciple
2) 将List<UserPrinciple>逐一转换为List<UserModel>, 其中UserModel包括了用户要的那些非公开属性, 通过使用反射取ExtensionGet()方法, 再调用该方法获得指定属性
3) 使用Linq对List<UserModel>进行过滤
大概试了下, 加入AD返回了2000个UserPrincipal对象, 每个对象取10个非公开属性,第2)步大概要用99%以上的时间。 为什么? 大量反射!这可不是EntityFramework,直接在SQLServer端就将过滤处理了,这是WebServer端干的活儿,严重拖累性能。
10分钟过去还得不到查询结果。 您再感受下客户气场……
解决的思路, 还是我们之前的ICollectionHandler,在将UserPrinciple 映射成UserModel之前, 先把过滤做了, 然后再把结果转换成UserModel, 这样能大大减少反射使用 的次数。可接下来的问题来了, 之前我们的CriteriaCollectionHandler类型中, 是使用type.GetProperty()方法来获取Public属性, 并进一步获取到属性值的,现在这些间接属性值改怎么办呢?
先来感受下代码:
- public sealed class AdvanceCriteriaCollectionHandler : CriteriaCollectionHandler
- {
- private string PropertyKey { get; set; }
- private MethodInfo GetPropertyMethod { get; set; }
- public AdvanceCriteriaCollectionHandler(Func<object, string, object> getPropertyMethod, string propertyKey, object target, ComparerEnum comparer)
- : base("", target, comparer)
- {
- GetPropertyMethod = getPropertyMethod.GetMethodInfo();
- this.PropertyKey = propertyKey;
- }
- private IQueryable<T> Filter<T>(IQueryable<T> source)
- {
- var type = typeof(T);
- var parameter = Expression.Parameter(type, "p"); //
- var constExpression = Expression.Constant(Target); // 转换为target的类型,以作比较
- var propertyAccess = Expression.Call(GetPropertyMethod, parameter, Expression.Constant(PropertyKey));
- Expression comparisionExpression;
- switch (Comparer)
- {
- case ComparerEnum.Eq:
- comparisionExpression = Expression.Equal(propertyAccess, constExpression);
- break;
- case ComparerEnum.Ne:
- comparisionExpression = Expression.NotEqual(propertyAccess, constExpression);
- break;
- case ComparerEnum.Lt:
- comparisionExpression = Expression.LessThan(propertyAccess, constExpression);
- break;
- case ComparerEnum.Gt:
- comparisionExpression = Expression.GreaterThan(propertyAccess, constExpression);
- break;
- case ComparerEnum.Le:
- comparisionExpression = Expression.LessThanOrEqual(propertyAccess, constExpression);
- break;
- case ComparerEnum.Ge:
- comparisionExpression = Expression.GreaterThanOrEqual(propertyAccess, constExpression);
- break;
- case ComparerEnum.StringLike:
- if (!(Target is string))
- {
- throw new NotSupportedException("StringLike is only suitable for string type property!");
- }
- var stringContainsMethod = typeof(CriteriaCollectionHandler).GetMethod("StringContains");
- comparisionExpression = Expression.Call(stringContainsMethod, propertyAccess, constExpression);
- break;
- default:
- comparisionExpression = Expression.Equal(propertyAccess, constExpression);
- break;
- }
- var compareExp = Expression.Lambda(comparisionExpression, parameter);
- var typeArguments = new Type[] { type };
- var methodName = "Where"; //sortOrder == SortDirection.Ascending ? "OrderBy" : "OrderByDescending";
- var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(compareExp));
- return source.Provider.CreateQuery<T>(resultExp);
- }
- public override ICollection<T> Execute<T>(ICollection<T> values)
- {
- var result = Filter(values.AsQueryable()).ToList();
- return result;
- }
- }
区别在哪呢? 构造函数中多了一个委托对象,这个委托对象就是用来处理取属性值的方法。三个参数分别对应了元素, 元素属性名称, 元素属性值(返回)。
其他的没有变化
使用示例(伪码)
- var criteria1 = new AdvanceCriteriaCollectionHandler(PrincipalExtensions.GetExtension, "Department", "HR" , comparerEnum.Eq); // department = HR
- var result = criteria1.Execute()
其中PrincipalExtensions.GetExtension 如下
- 1 public static class PrincipalExtensions
- 2 {
- 3 private static readonly MethodInfo ExtensionSet = typeof(Principal).GetMethod("ExtensionSet", BindingFlags.NonPublic | BindingFlags.Instance);
- 4 private static readonly ADSIUserHandler userHandler = new ADSIUserHandler();
- 5 public static void SetExtension<T>(this Principal principal, String key, T value)
- 6 {
- 7 ExtensionSet.Invoke(principal, new object[] { key, value });
- 8
- 9 }
- 10 private static readonly MethodInfo ExtensionGet = typeof(Principal).GetMethod("ExtensionGet", BindingFlags.NonPublic | BindingFlags.Instance);
- 11
- 12
- 13 public static T GetExtension<T>(this Principal principal, String key)
- 14 {
- 15 try
- 16 {
- 17 var values = (object[])ExtensionGet.Invoke(principal, new[] { key });
- 18
- 19 if (values == null || values.Length == 0)
- 20 {
- 21 return default(T);
- 22 }
- 23 return (T)values[0];
- 24
- 25 }
- 26 catch
- 27 {
- 28 return default(T);
- 29 }
- 30 }
- 31
- 32
- 33 public static object GetExtension(object principal, String key)
- 34 {
- 35
- 36 try
- 37 {
- 38 object[] values = (object[])ExtensionGet.Invoke(principal, new[] { key });
- 39 if (values == null || values.Length == 0)
- 40 {
- 41 return null;
- 42 }
- 43 return values[0];
- 44
- 45 }
- 46 catch
- 47 {
- 48 return null;
- 49 }
- 50 }
- 51
- 52
- 53 }
然后在获取所有UserPrinciple的后面立刻加上集合过滤(伪码):
- ICollection<UserPrincipal> allUsers = ADSIHelper.GetUsers(recursive, searchBase, keywords).OfType<UserPrincipal>().ToList();
- if (advCriteria!= null) //advanced criteria collection handler
- {
- allUsers = advCriteria.Execute(allUsers);
- }
return allUsers.ToModels();
重新估算下, 之前是2000*10 = 20,000次反射调用
现在,假如删选完成后只有100个结果, 则反射调用的次数是 2000*1 + 100*10 = 3,000 次反射调用。
不仅仅速度会明显变快,而且能和之前的CollectionHandler处理的思路保持一致,同样能支持任意字段的过滤。
使用Expression来实现对集合的任意字段过滤先介绍到这里。 除了筛选过滤,常见的还有排序和分页, 后面我再陆续介绍。
使用Expression实现数据的任意字段过滤(2)的更多相关文章
- 使用Expression实现数据的任意字段过滤(1)
在项目常常要和数据表格打交道. 现在BS的通常做法都是前端用一个js的Grid控件, 然后通过ajax的方式从后台加载数据, 然后将数据和Grid绑定. 数据往往不是一页可以显示完的, 所以要加分页: ...
- 齐博x1 万能fun 调用任意数据表 任意字段就是这么任性调用
列举了几个常用的查询进行简单封装,虽然系统也有内置的但是很多人不大会就二次封装简化了一下. 这里只封装了一个条件 多个条件的自己再封装或者用标签解决比较好 这里只是说fun可以万能调用 1获取任意表的 ...
- 写出java8实现对List<User>中的username字段过滤出不等于张三的数据
写出java8实现对List<User>中的username字段过滤出不等于张三的数据... 对...这个是一道面试题.当时没有看过java8的新特性...所以有点懵. 看完之后感觉 真. ...
- Python黑客编程基础3网络数据监听和过滤
网络数据监听和过滤 课程的实验环境如下: • 操作系统:kali Linux 2.0 • 编程工具:Wing IDE • Python版本:2.7.9 • 涉及 ...
- 处理json数据的空数据为任意字符
处理json数据的空数据为任意字符 有时候从后台返回来的数据需要处理一下,根据实际开发需求,不能在页面上直接显示空字符,需要显示为"无内容"或者其他字段,而有些json数据结构比较 ...
- ASP.NET实现二维码 ASP.Net上传文件 SQL基础语法 C# 动态创建数据库三(MySQL) Net Core 实现谷歌翻译ApI 免费版 C#发布和调试WebService ajax调用WebService实现数据库操作 C# 实体类转json数据过滤掉字段为null的字段
ASP.NET实现二维码 using System;using System.Collections.Generic;using System.Drawing;using System.Linq;us ...
- MVC中构建Linq条件、排序、Selector字段过滤
代码: System.Linq.Expressions.Expression<Func<Domain.S_ROLE, bool>> expressWhere1 = (c =&g ...
- 如何在K3 WISE BOS集成开发工具中自定义字段过滤条件
1.结论 对于输入过滤条件后BOS报“列名不正确”的过滤条件,要在列名前增加x2标识 无效的过滤 FNumber ,,,,,) 正确的过滤 x2.FNumber ,,,,,) 2.完全可以不看的探索过 ...
- SQL批量更新数据库中所有用户数据表中字段类型为tinyint为int
--SQL批量更新数据库中所有用户数据表中字段类型为tinyint为int --关键说明:--1.从系统表syscolumns中的查询所有xtype='48'的记录得到类型为[tinyint]的字段- ...
随机推荐
- 用FSM一键制作逐帧动画雪碧图 Vue2 + webpack
因为工作需要要将五六十张逐帧图拼成雪碧图,网上想找到一件制作工具半天没有找到,就自己用canvas写了一个. 写成之后就再没有什么机会使用了,因此希望有人使用的时候如果遇到bug了能及时反馈给我. 最 ...
- var和dynamic的区别
1.var 1.均是声明动态类型的变量. 2.在编译阶段已经确定类型,在初始化的时候必须提供初始化的值. 3.无法作为方法参数类型,也无法作为返回值类型. 2.dynamic 1.均是声明动态类型的变 ...
- Twproject Gantt开源甘特图功能扩展
1.Twproject Gantt甘特图介绍 Twproject Gantt 是一款基于 jQuery 开发的甘特图组件,也可以创建其它图表,例如任务树(Task Trees).内置编辑.缩放和 CS ...
- 【WPF】日常笔记
本文专用于记录WPF开发中的小细节,作为备忘录使用. 1. 关于绑定: Text ="{Binding AnchorageValue,Mode=TwoWay,UpdateSourceTrig ...
- 使用Git Bash远程添加分支和简单部署你的静态页面
新建一个分支:git branch mybranch(mybranch你的分支名字) 切换到你的新分支: git checkout mybranch 将新分支发布在github上: git push ...
- cesium核心类Viewer简介
1.简单描述Viewer Viewer类是cesium的核心类,是地图可视化展示的主窗口,cesium程序应用的切入口,扮演必不可少的核心角色. 官网的英文解析如下: A base widget fo ...
- ASP.NET MVC 系列随笔汇总[未完待续……]
ASP.NET MVC 系列随笔汇总[未完待续……] 为了方便大家浏览所以整理一下,有的系列篇幅中不是很全面以后会慢慢的补全的. 学前篇之: ASP.NET MVC学前篇之扩展方法.链式编程 ASP. ...
- Spring集成MyBatis
本文原创,原文地址为http://www.cnblogs.com/fengzheng/p/5045105.html 如果觉得Hibernate不够灵活,可以尝试用Mybatis.相比于Hibernat ...
- 使用R画地图数据
用R画地图数据 首先,从这里下载中国地图的GIS数据,这是一个压缩包,完全解压后包含三个文件(bou2_4p.dbf.bou2_4p.shp和bou2_4p.shx),将这三个文件解压到同一个目录下. ...
- Protobuf使用规范分享
一.Protobuf 的优点 Protobuf 有如 XML,不过它更小.更快.也更简单.它以高效的二进制方式存储,比 XML 小 3 到 10 倍,快 20 到 100 倍.你可以定义自己的数据结构 ...