上一篇《使用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)的更多相关文章

  1. 使用Expression实现数据的任意字段过滤(1)

    在项目常常要和数据表格打交道. 现在BS的通常做法都是前端用一个js的Grid控件, 然后通过ajax的方式从后台加载数据, 然后将数据和Grid绑定. 数据往往不是一页可以显示完的, 所以要加分页: ...

  2. 齐博x1 万能fun 调用任意数据表 任意字段就是这么任性调用

    列举了几个常用的查询进行简单封装,虽然系统也有内置的但是很多人不大会就二次封装简化了一下. 这里只封装了一个条件 多个条件的自己再封装或者用标签解决比较好 这里只是说fun可以万能调用 1获取任意表的 ...

  3. 写出java8实现对List<User>中的username字段过滤出不等于张三的数据

    写出java8实现对List<User>中的username字段过滤出不等于张三的数据... 对...这个是一道面试题.当时没有看过java8的新特性...所以有点懵. 看完之后感觉 真. ...

  4. Python黑客编程基础3网络数据监听和过滤

    网络数据监听和过滤 课程的实验环境如下: •      操作系统:kali Linux 2.0 •      编程工具:Wing IDE •      Python版本:2.7.9 •      涉及 ...

  5. 处理json数据的空数据为任意字符

    处理json数据的空数据为任意字符 有时候从后台返回来的数据需要处理一下,根据实际开发需求,不能在页面上直接显示空字符,需要显示为"无内容"或者其他字段,而有些json数据结构比较 ...

  6. 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 ...

  7. MVC中构建Linq条件、排序、Selector字段过滤

    代码: System.Linq.Expressions.Expression<Func<Domain.S_ROLE, bool>> expressWhere1 = (c =&g ...

  8. 如何在K3 WISE BOS集成开发工具中自定义字段过滤条件

    1.结论 对于输入过滤条件后BOS报“列名不正确”的过滤条件,要在列名前增加x2标识 无效的过滤 FNumber ,,,,,) 正确的过滤 x2.FNumber ,,,,,) 2.完全可以不看的探索过 ...

  9. SQL批量更新数据库中所有用户数据表中字段类型为tinyint为int

    --SQL批量更新数据库中所有用户数据表中字段类型为tinyint为int --关键说明:--1.从系统表syscolumns中的查询所有xtype='48'的记录得到类型为[tinyint]的字段- ...

随机推荐

  1. 深入浅出JavaScript之原型链&继承

    Javascript语言的继承机制,它没有"子类"和"父类"的概念,也没有"类"(class)和"实例"(instanc ...

  2. PHP之Memcache缓存详解

         Mem:memory缩写(内存):内存缓存 1.  断电或者重启服务器内存数据即消失,即临时数据: Memcache默认端口:11211 存入方式:key=>>value    ...

  3. 基于注解的bean配置

    基于注解的bean配置,主要是进行applicationContext.xml配置.DAO层类注解.Service层类注解. 1.在applicationContext.xml文件中配置信息如下 &l ...

  4. Maven 代理设置

    在maven的安装目录下 %MAVEN_HOME%/conf/setting.xml 中进行设置 <proxies>    <!-- proxy     | Specificatio ...

  5. 使用python自动生成docker nginx反向代理配置

    由于在测试环境上用docker部署了多个应用,而且他们的端口有的相同,有的又不相同,数量也比较多,在使用jenkins发版本的时候,不好配置,于是想要写一个脚本,能在docker 容器创建.停止的时候 ...

  6. PHP设计模式(一)简单工厂模式 (Simple Factory For PHP)

    最近天气变化无常,身为程序猿的寡人!~终究难耐天气的挑战,病倒了,果然,程序猿还需多保养自己的身体,有句话这么说:一生只有两件事能报复你:不够努力的辜负和过度消耗身体的后患.话不多说,开始吧. 一.什 ...

  7. 品牌营销:不要Beat,要逼格!

             品牌营销:不要Beat,要逼格! 奥美的创始人大卫·奥格威说,广告营销应当是"具有风度的推销产品".而当下的营销手段,"风度"早已被抛之脑后, ...

  8. 打开程序总是会提示“Enter password to unlock your login keyring” ,如何成功关掉?

    p { margin-bottom: 0.1in; line-height: 120% } 一.一开始我是按照网友所说的 : rm -f ~/.gnome2/keyrings/login.keyrin ...

  9. .NET面试题系列[5] - 垃圾回收:概念与策略

    面试出现频率:经常出现,但通常不会问的十分深入.通常来说,看完我这篇文章就足够应付面试了.面试时主要考察垃圾回收的基本概念,标记-压缩算法,以及对于微软的垃圾回收模板的理解.知道什么时候需要继承IDi ...

  10. React 其实比 MVVM 架构更加卡顿

    React 号称通过引入 Virtual DOM 带来了性能的提升,而其实 React 之所以需要 Virtual DOM,是因为它的架构下,state 的变更是全量的,然后触发 render 返回全 ...