一般的程序员做上几年以后, 或多或少的都有些代码的积累, 我也不例外. 作为微软技术程序员, 自从Linq和EF出来之后, 就基本上爱不释手了, 且不说执行效率的问题, 单单就开发效率和代码的可移植性上讲, 都是微软技术常规开发首选无二了. 于是终于丢掉了奴隶社会的.NET三层, 进入了EF的封建制了, 然后, 就发现持久化层的代码越写越少, 越写越精炼, 最后好像简直就是个万金油啊, 拿到哪里哪里可以用. 还有因为Lambda 表达式可以做为查询代码的参数, 就导致, 服务器端单单就数据访问层代码就浓缩到了一个文件中, 而且还不需要写过于复杂的代码就可以写出使用泛型, 适合各种增删改查的动态代码, 如下面的查询:

  public IQueryable<T> ExecuteQuery<T>(Fun<T, bool> where, Fun<T, string> orderby, int pageIndex, int pageSize, out int total, params string[] includes) where T : class {...}

  一度感觉心里美美的, 好像世界从此就清净了. 直到后来做Web开发的时候, 发现了一个这套机制难以解决的问题,  那就是如何将查询应用到客户端复杂的过滤条件上了?

  那为什么不能了? 因为Lambda 表达式本身就是动态委托, 这种类型是不能从客户端(js)构造出来, 作为参数传递到服务器端去执行的, 那么怎么办了?

  经过一番研究, 终于发现了可实现的方式, 原来在System.Linq.Expressions命名空间下的Expression类提供了大量方法, 用于构造动态语法, 于是从只需要定义一套查询表达式规则, 然后客户端去写表达式, 服务器端收到后把它解析成Lambda表达式就可以被EF执行了, 至此, 好像发现了新大陆一样又欣喜若狂了一番.

  现在, 随着.NET开源, Oracle和Mysql开始支持EF6, 直到Webapi开始支持oData, 貌似一场新的技术改革又要开始了. 我又投入到了新技术孜孜不倦的追求当中.

  虽然oData是如此之好用, 以至于从此从客户端接受增删改查什么的都成了浮云,  但是许多程序员还在维护着很多旧代码, 许多新程序员需要技术指导和提高, 许多时间以后我自己或许也会忘记如何去写动态表达式, 所以把核心部分代码贴出来, 大家分享一下, 不喜勿喷哦.

  DbContext的扩展查询方法:

  1. 1 public static IQueryable<T> ExecuteQuery<T>(this DbContext ctx, QueryExpression query) where T : class
  2. {
  3. try
  4. {
  5. IQueryable<T> queryable = ctx.Set<T>();
  6. if (query != null)
  7. {
  8. if (query.Include != null && query.Include.Count != )
  9. {
  10. foreach (var x in query.Include)
  11. {
  12. queryable = queryable.Include<T>(query.Include[]);
  13. }
  14. }
  15. ParameterExpression param = Expression.Parameter(typeof(T), CommonClass.Anonymous);
  16. if (query.Filter != null && query.Filter.Count != )
  17. {
  18. Expression filter = Expression.Constant(true);
  19. foreach (var x in query.Filter)
  20. {
  21. filter = filter.AddQueryExpression<T>(param, x);
  22. }
  23. Expression<Func<T, bool>> where = arg => true;
  24. where = where.Update(filter, new List<ParameterExpression> { param });
  25. queryable = queryable.Where(where);
  26. }
  27. if (query.OrderBy != null && query.OrderBy.Count != )
  28. {
  29. Expression<Func<T, string>> orderBy = arg => CommonClass.StateField;
  30. IOrderedQueryable<T> orderByQueryable = queryable.OrderBy(orderBy);
  31. foreach (var x in query.OrderBy)
  32. {
  33. Expression exp = Expression.Property(param, x.Field);
  34. orderBy = orderBy.Update(exp, new List<ParameterExpression> { param });
  35. orderByQueryable = x.Asc ? orderByQueryable.ThenBy(orderBy) : orderByQueryable.ThenByDescending(orderBy);
  36. }
  37. queryable = orderByQueryable.AsQueryable<T>();
  38. }
  39. if (query.Pager != null)
  40. {
  41. query.Pager.Total = queryable.Count();
  42. queryable = queryable.Skip((query.Pager.PageIndex - ) * query.Pager.PageSize).Take(query.Pager.PageSize);
  43. }
  44. }
  45. return queryable;
  46. }
  47. catch (Exception ex)
  48. {
  49. throw ex;
  50. }
  51. }
  1. public static Expression AddQueryExpression<T>(this Expression exp, ParameterExpression param, DataFilter filter)
  2. {
  3. try
  4. {
  5. if (param != null && filter != null)
  6. {
  7. Expression mexp = null;
  8. BinaryExpression bexp = null;
  9. PropertyInfo property = typeof(T).GetProperty(filter.Field);
  10. if (property != null)
  11. {
  12. Type type = property.PropertyType;
  13. object value = Convert.ChangeType(filter.Value, type);
  14. switch (filter.Operation)
  15. {
  16. //methods operation
  17. case DataOperation.Contains:
  18. case DataOperation.StartsWith:
  19. case DataOperation.EndsWith:
  20. mexp = Expression.Call(Expression.Property(param, filter.Field), type.GetMethod(filter.Operation.ToString()), Expression.Constant(value));
  21. exp = Expression.AndAlso(exp, mexp);
  22. break;
  23. //other operation
  24. case DataOperation.Equal:
  25. bexp = Expression.Equal(Expression.Property(param, filter.Field), Expression.Constant(value));
  26. exp = Expression.AndAlso(exp, bexp);
  27. break;
  28. case DataOperation.NotEqual:
  29. bexp = Expression.NotEqual(Expression.Property(param, filter.Field), Expression.Constant(value));
  30. exp = Expression.AndAlso(exp, bexp);
  31. break;
  32. case DataOperation.GreaterThan:
  33. bexp = Expression.GreaterThan(Expression.Property(param, filter.Field), Expression.Constant(value));
  34. exp = Expression.AndAlso(exp, bexp);
  35. break;
  36. case DataOperation.GreaterThanOrEqual:
  37. bexp = Expression.GreaterThanOrEqual(Expression.Property(param, filter.Field), Expression.Constant(value));
  38. exp = Expression.AndAlso(exp, bexp);
  39. break;
  40. case DataOperation.LessThan:
  41. bexp = Expression.LessThan(Expression.Property(param, filter.Field), Expression.Constant(value));
  42. exp = Expression.AndAlso(exp, bexp);
  43. break;
  44. case DataOperation.LessThanOrEqual:
  45. bexp = Expression.LessThanOrEqual(Expression.Property(param, filter.Field), Expression.Constant(value));
  46. exp = Expression.AndAlso(exp, bexp);
  47. break;
  48. default:
  49. break;
  50. }
  51. }
  52. }
  53. return exp;
  54. }
  55. catch (Exception ex)
  56. {
  57. throw ex;
  58. }
  59. }

其中的QueryExpression是我自己定义的查询表达式对象, 可以从客户端传递.

打完收工!

如何使用 Entity Framework 构造动态查询表达式的更多相关文章

  1. 关于Entity Framework自动关联查询与自动关联更新导航属性对应的实体注意事项说明

    一.首先了解下Entity Framework 自动关联查询: Entity Framework 自动关联查询,有三种方法:Lazy Loading(延迟加载),Eager Loading(预先加载) ...

  2. Entity Framework入门教程: Entity Framework支持的查询方式

    Entity Framework支持的查询方式有三种 LINQ to Entities Entity SQL Native SQL [LINQ to Entities] LINQ(语言集成查询)是从V ...

  3. 在Linq to sql 和 Entity framework 中使用lambda表达式实现left join

    在Linq to sql 和 Entity framework 中使用lambda表达式实现left join 我们知道lambda表达式在Linq to sql 和 Entity framework ...

  4. Entity Framework常用的查询方式

    Entity Framework支持的查询方式有三种 LINQ to Entities Entity SQL Native SQL [LINQ to Entities] LINQ(语言集成查询)是从V ...

  5. Entity Framework做IN查询

    开发中遇到的Too high level of nesting for select错误 项目使用了Entity Framework结合Mysql, 遇到了一个非常奇怪的性能问题,一个看起来非常简单的 ...

  6. Entity Framework Core Like 查询揭秘

    在Entity Framework Core 2.0中增加一个很酷的功能:EF.Functions.Like(),最终解析为SQL中的Like语句,以便于在 LINQ 查询中直接调用. 不过Entit ...

  7. Entity Framework中实现查询的几种方法

    在介绍几种方法前,献上一张图,希望图的作者不要追究我的盗图之过.本文的内容是我自学时的笔记,自学的内容来自网络.手打的代码,切不可直接复制过去用,会有好多错别字什么的. Entity SQL 类似于S ...

  8. Entity Framework 7 动态 DbContext 模型缓存 ModelCaching

    EF7里实例化DbContext变的有点麻烦了, 下面这个基类会有所帮助: public abstract class BaseDbContext : DbContext { private stri ...

  9. Entity Framework Linq 动态组合where条件

    public static class PredicateExtensions { public static Expression<Func<T, bool>> True&l ...

随机推荐

  1. Android声音播放实例代码

    布局文件: <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android=&q ...

  2. js+html5双人五子棋(源码下载)

    代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" c ...

  3. .net源码分析 - ConcurrentDictionary<TKey, TValue>

    List源码分析 Dictionary源码分析 ConcurrentDictionary源码分析 继上篇Dictionary源码分析,上篇讲过的在这里不会再重复 ConcurrentDictionar ...

  4. HttpClient通过Post上传多个文件

    public static String sendFilesPost(String url, String fileNames) { HttpClient httpClient = null; Htt ...

  5. 2个很有趣、耐思考的C语言算法

    1. 输入10个整数,任意相邻的两个数不同,输出所有的递增,递减序列 比如: 输入:1 5 9 8 12 21 3 0 -1 9 输出: 1 5 9 9 8 8 12 21 21 3 0 -1 -1 ...

  6. tomcat 自定义classpath(亲自测试)

    因为一直以来使用tomcat和weblogic作为应用服务器为主,最近在升级新中间件的过程中遇到一个问题,我们的web前端应用现在升级是进行全量包升级的,因为现在的系统架构为前端和后端通过rpc框架交 ...

  7. Ajax的核心对象创建步骤

    * Ajax具有核心对象 * XMLHttpRequest对象 * 如何创建XMLHttpRequest对象 function getXhr(){ // 声明XMLHttpRequest对象 var ...

  8. ASP.NET MVC Autofac自动注入

    依赖注入容器有很多插件,我用过Unity和Autofac,这两个插件给我最明显的感觉就是Autofac很快,非常的快,毕竟是第三方开发的,而Unity相对而言性能比较稳定 下面附上Autofac自动注 ...

  9. Android开发学习——打电话应用

    打电话应用 system/app/phone.apk  这个是打电话应用,这个Java API 不允许应用级程序员改写,系统级才可以 system/app/dialer.apk  这个是拨号器应用,可 ...

  10. iOS 中常用的对密码进行MD5加密

    iOS中MD5加密 标签(空格分隔): iOS MD5 + (NSString *)MD5:(NSString *)str { const char *cStr = [str UTF8String]; ...