没猜错的话, 你们一定会和一大堆查询条件过不去, 重复的写,反复的写, 写到山崩地裂.

今天看了园友的文字:
实体框架高级应用之动态过滤 EntityFramework DynamicFilters

我把我的处理方式给大家分享一下.

查询条件可以是这样的,有很多:

也可以是这样的, 没有几个:

我数了一下,我们系统里的Controller , 112个, 68个查询条件.

如果把这 68个查询条件转换为查询代码的话, 想想都蛋疼啊, 那得写多少啊.

比如这样, 重复,机械,没有营养:

         public IEnumerable<CREDIT_ASSESS_RESULT> GetCreditResults(CreditAssessResultCondition condition)
         {
             using (var db = new Entities())
             {
                 IQueryable<CREDIT_ASSESS_RESULT> query = db.CREDIT_ASSESS_RESULT.Where(q => q.STATUS >= );
                 )
                 {
                     query = query.Where(q => q.CARRIER_ID == condition.CARRIER_ID);
                 }

                 )
                 {
                     query = query.Where(q => q.LOCAL_COMPANY_ID == condition.COMPANY_ID);
                 }

                 if (condition.ROUTE_ID.HasValue)
                 {
                     query = query.Where(q => q.APPLYTO_ROUTEID == condition.ROUTE_ID);
                 }

                 if (condition.CUSTOMER_TYPE.HasValue)
                 {
                     query = query.Where(q => q.APPLYTO_CUSTOMER == condition.CUSTOMER_TYPE);
                 }

                 if (condition.CREDIT_PERIOD.HasValue)
                 {
                     //String period = condition.CREDIT_PERIOD.Value.ToString();
                     query = query.Where(q => q.PERIOD == (int)condition.CREDIT_PERIOD.Value);
                 }

                 if (condition.CREDIT_YEAR.HasValue)
                 {
                     query = query.Where(q => q.YEARS.Value == condition.CREDIT_YEAR.Value);
                 }

                 )
                 {
                     query = query.Where(q => q.MONTHS == condition.CREDIT_MONTH);
                 }
                 )
                 {
                     query = query.Where(q => q.SEASONS == condition.CREDIT_SEASON);
                 }

                 if (!String.IsNullOrWhiteSpace(condition.CUSTOMER_CODE))
                 {
                     query = query.Where(q => q.COMPANY_ID == condition.CUSTOMER_ID && (q.COMPANY_NAME_CN.ToUpper().Contains(condition.CUSTOMER_CODE.ToUpper()) ||
                         q.COMPANY_NAME_EN.ToUpper().Contains(condition.CUSTOMER_CODE.ToUpper())));
                 }

                 if (condition.CustomerSearch.HasValue && condition.CustomerSearch.Value)
                 {
                     query = query.Where(q => q.STATUS > );
                 }

                 return query.OrderByDescending(q => q.CREATE_DATETIME).ThenBy(q => q.APPLYTO_COMPANY).ThenBy(q => q.COMPANY_NAME_EN).DoPage(condition.Pager).ToList();
             }
         }

为了解放同志们, 我借助 DynamicLinq  写了个简单的解决方案:

1, 先看查询条件的写法:

     public class RateSearchCondition : BaseQuery<RATES> {

         public decimal? Carrier {
             get;
             set;
         }

         [MapTo("ROUTE_CODE", IgnoreCase = true)]
         public string Route {
             get;
             set;
         }

         [MapTo("POL_CODE", IgnoreCase = true)]
         public string Pol {
             get;
             set;
         }

         [MapTo("POD_CODE", IgnoreCase = true)]
         public string Pod {
             get;
             set;
         }

         /// <summary>
         /// 启运地
         /// </summary>
         [MapTo("FRONT_CODE")]
         public string OrginCode {
             get;
             set;
         }

         /// <summary>
         /// 目的地
         /// </summary>
         [MapTo("PFD_CODE")]
         public string DestCode {
             get;
             set;
         }

         [MapTo("EFFECTIVE_DATE")]
         public DateTime? EffectiveDate {
             get;
             set;
         }

         [MapTo("EXPIRATION_DATE")]
         public DateTime? ExpirationDate {
             get;
             set;
         }

         public Status? StatusEnum {
             get;
             set;
         }

         [MapTo("STATUS")]
         public decimal? StatusValue {
             get {
                 return (decimal?)this.StatusEnum;
             }
         }

         [MapTo("SCHEDULE_ID")]
         public decimal? ScheduleID {
             get;
             set;
         }

         public string Vessel {
             get;
             set;
         }

         public string Voyage {
             get;
             set;
         }

         /// <summary>
         /// 销售公司
         /// </summary>
         public decimal? Company {
             get;
             set;
         }

         public enum Status {
             [Description("作废")]
             Invalid = -,
             [Description("草稿")]
             Draft = ,
             [Description("已发布")]
             Published = ,
             [Description("历史")]
             History = ,
         }

         public string VesselName {
             get;
             set;
         }

         public bool IncludeHistory {
             get;
             set;
         }

         [MapTo("RATE_NO", IgnoreCase = true)]
         public string RateNo {
             get;
             set;
         }
     }

简单的类定义而已, 只不过某些属性上加了  MapToAttribute 特性, 有些没有加.

这些加上了 MapTo 的, 就是本文说的.

2, 看一下查询的写法:

         public IEnumerable<RATES> Search(RateSearchCondition cond) {
             using (var db = new Entities()) {
                 var query = cond.Filter(db.RATES.Where(r => !r.DELETE_MARK));

                 if (!(cond.IncludeHistory || cond.StatusEnum == RateSearchCondition.Status.History)) {
                     query = query.Where(m => m.STATUS != (int)RateSearchCondition.Status.History)
                         .OrderByDescending(r => r.MODIFY_DATETIME);
                 } else
                     query = query.OrderByDescending(r => r.CREATEBY ?? );

                 return query
                     .DoPage(cond.Pager)
                     .ToList();
             }
         }

这样看, 代码是不是清爽很多?

那么多查询条件, 基本都浓缩进了 cond.Filter(...) 中了, 如果要加其它的查询条件, 只需要改一下查询条件的类, 并加上 MapTo 就可以了.

不能浓缩进去的, 直接写在代码里, 反正也没有几个.

3, 看一下 MapTo 的定义:

     /// <summary>
     /// 用于 BaseQuery
     /// </summary>
     [AttributeUsage(AttributeTargets.Property)]
     public class MapToAttribute : Attribute {

         /// <summary>
         /// 映射到的属性
         /// </summary>
         public string Field {
             get;
             set;
         }

         /// <summary>
         /// 比较类型
         /// </summary>
         public MapToOpts Opt {
             get;
             set;
         }

         /// <summary>
         /// 是否忽略大小写
         /// </summary>
         public bool IgnoreCase {
             get;
             set;
         }

         /// <summary>
         ///
         /// </summary>
         /// <param name="field"></param>
         public MapToAttribute(string field) {
             if (string.IsNullOrEmpty(field))
                 throw new ArgumentNullException("field");

             this.Field = field;
         }

     }

     /// <summary>
     /// 比较类型
     /// </summary>
     public enum MapToOpts {
         /// <summary>
         /// 等于
         /// </summary>
         Equal,

         /// <summary>
         /// 不等于
         /// </summary>
         NotEqual,

         /// <summary>
         /// 大于
         /// </summary>
         Gt,

         /// <summary>
         /// 大于等于
         /// </summary>
         GtOrEqual,

         /// <summary>
         /// 小于
         /// </summary>
         Lt,

         /// <summary>
         /// 小于等
         /// </summary>
         LtOrEqual,

         /// <summary>
         /// 以 XXX 开始(字符串)
         /// </summary>
         StartWith,

         /// <summary>
         /// 以XXX结尾(字符串)
         /// </summary>
         EndWith,

         /// <summary>
         /// 包含XXX(字符串)
         /// </summary>
         Include
     }

从 MapToOpts 可以看出, 基本的大于,小于,等于,不等于, 开始,包含,结束这样的查询条件都可以涵盖到.

但是像 是否包含在集合中 / And / Or 操作是不支持的,  它们需要写在查询方法里, 所以标题我就写的是: 基本数据过滤

4, BaseQuery 的定义:

     [Serializable]
     public class BaseQuery {

         private Pager pager = null;
         public Pager Pager {
             get {
                 if (this.pager == null)
                     this.pager = new Pager();
                 return this.pager;
             }
             set {
                 this.pager = value;
             }
         }

         private bool allowPage = true;
         /// <summary>
         /// 是否分页
         /// </summary>
         [DisableBinding]
         public bool AllowPage {
             get {
                 return this.allowPage;
             }
             set {
                 this.allowPage = value;
             }
         }
     }

     [Serializable]
     public class BaseQuery<T> : BaseQuery where T : class {

         public IQueryable<T> Filter(IQueryable<T> source) {
             var ps = this.GetType()
                 .GetProperties()
                 .ToList();

             ps.ForEach(p => {
                 var mapTo = p.GetCustomAttribute<MapToAttribute>();
                 if (mapTo != null) {
                     var st = typeof(T).GetProperty(mapTo.Field);
                     if (st != null) {
                         var opt = string.Empty;
                         switch (mapTo.Opt) {
                             case MapToOpts.Equal:
                                 opt = "==";
                                 break;
                             case MapToOpts.NotEqual:
                                 opt = "!=";
                                 break;
                             case MapToOpts.Gt:
                                 opt = ">";
                                 break;
                             case MapToOpts.Lt:
                                 opt = "<";
                                 break;
                             case MapToOpts.GtOrEqual:
                                 opt = ">=";
                                 break;
                             case MapToOpts.LtOrEqual:
                                 opt = "<=";
                                 break;
                         }

                         if (!string.IsNullOrEmpty(opt)) {
                             var v = p.GetValue(this);
                             if (v != null) {
                                 string cond = "";
                                 if (v.GetType() == typeof(string) && mapTo.Opt == MapToOpts.Equal && mapTo.IgnoreCase) {
                                     if (!string.IsNullOrWhiteSpace(v.ToString()))
                                     {
                                         cond = string.Format("{0}.ToUpper() {1} @0", st.Name, opt);
                                         source = source.Where(cond, ((string)v).ToUpper());
                                     }
                                 } else {
                                     cond = string.Format("{0} {1} @0", st.Name, opt);
                                     source = source.Where(cond, v);
                                 }

                             }
                         } else {
                             var cond = string.Empty;

                             var v = (string)p.GetValue(this);
                             if (v == null || string.IsNullOrEmpty((string)v))
                                 return;

                             v = v.Replace("\"", "");

                             if (string.IsNullOrEmpty(v))
                                 return;

                             var ignoreCaseStr = mapTo.IgnoreCase ? ".ToUpper()" : "";
                             if (mapTo.IgnoreCase)
                                 v = v.ToUpper();

                             switch (mapTo.Opt) {
                                 case MapToOpts.Include:
                                     cond = string.Format("{0}{1}.IndexOf(\"{2}\") != -1", st.Name, ignoreCaseStr, v);
                                     break;
                                 case MapToOpts.StartWith:
                                     cond = string.Format("{0}{1}.StartsWith(\"{2}\")", st.Name, ignoreCaseStr, v);
                                     break;
                                 case MapToOpts.EndWith:
                                     cond = string.Format("{0}{1}.EndsWith(\"{2}\")", st.Name, ignoreCaseStr, v);
                                     break;
                             }

                             if (!string.IsNullOrEmpty(cond)) {
                                 source = source.Where(cond);
                             }

                         }
                     }
                 }
             });

             return source;
         }
     }

Filter 方法先获取泛型参数的所有 Property, 然后遍例, 获取加到 Property 上的 MapToAttribute 进行相关的操作.

如果某个条件的值是 null , 说明这个条件跳过.

如果是字符类型的条件, 会跟据是否 IgnoreCase 应用 ToUpper , 因为我们用的是 ORACLE 数据, 大小写敏感. 还会应用 IndexOf, StartsWith, EndsWidth

----------------------------

好啦 , 就这样.

EF 基本数据过滤的更多相关文章

  1. asp.net MVC EF Where 过滤条件怎么写

    做.Net开发的肯定都知道.Net Sql语句有个SqlParameter 一般用来做过滤判断逻辑写,那么到了EF 了还有这样的写法嘛?答案肯定是有的了,这里我只是把最粗糙和简单的写法罗列一些,具体封 ...

  2. EF架构~过滤导航属性等,拼接SQL字符串

    拼接T-SQL串,并使它具有通用性 好处:与服务器建立一次连接,给服务器发一条SQL命令,即可实现 代码如下: 1 /// <summary> 2 /// 构建Insert语句串 3 // ...

  3. .NET深入实战系列--EF到底怎么写过滤条件

    本文唯一访问地址:http://www.cnblogs.com/yubaolee/p/DynamicLinq.html 对于系统开发来说,按不同字段进行过滤查询是一种常见的需求.在EF中通常的做法是: ...

  4. .NET深入实战系列--EF到底怎么写过滤条件(转)

    原文来自:http://www.cnblogs.com/yubaolee/p/DynamicLinq.html 对于系统开发来说,按不同字段进行过滤查询是一种常见的需求.在EF中通常的做法是: /// ...

  5. Linux如何查看进程是否存活

    ps  -ef  | grep nginx ps -ef | grep(过滤) 进程名字

  6. Shell【常用知识总结】

    一.常用知识总结 1.特殊变量($0,@,#,*,?) $0:当前脚本的文件名. $n:n是一个数字,表示第几个参数. $#:传递给脚本或函数的参数个数. $*:传递给脚本或函数的所有参数.当被双引号 ...

  7. %E3%80%90%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B%E3%80%91

    "%3Cdiv%20class%3D%22htmledit_views%22%20id%3D%22content_views%22%3E%0A%20%20%20%20%20%20%20%20 ...

  8. EF联合查询,如何设置条件过滤从表数据

    最近在使用EF进行联合查询过程中,遇到了一件不开心的事情. 已禁用懒加载 var post = await _repository.GetMyPostById(blogId, postId).AsNo ...

  9. 在ASP.NET Core中通过EF Core实现一个简单的全局过滤查询

    前言 不知道大家是否和我有同样的问题: 一般在数据库的设计阶段,会制定一些默认的规则,其中有一条硬性规定就是一定不要对任何表中的数据执行delete硬删除操作,因为每条数据对我们来说都是有用的,并且是 ...

随机推荐

  1. Spring中Template模式与callback的结合使用浅析

    Spring不论是与ibatis,还是与Hibernate的结合中,都使用到了Template模式与callback技术,来达到简化代码实现的目的.Template模式也即模板模式,用于对一些不太变化 ...

  2. 问题解决——WSAAsyncSelect模型 不触发 FD_CLOSE

    ==================================声明================================== 本文原创,转载在正文中显要的注明作者和出处,并保证文章的完 ...

  3. XShell上传、下载文件(使用sz与rz命令)!

    rz,sz是Linux/Unix同Windows进行ZModem文件传输的命令行工具.优点就是不用再开一个sftp工具登录上去上传下载文件. sz:将选定的文件发送(send)到本地机器rz:运行该命 ...

  4. Linux 常用命令行

    Linux常用命令行 第一部分: cd命令 第二部分:文件操作 第三部分:压缩包操作

  5. html3秒跳转

    <script>     setTimeout( 'window.location= "home.jsp " ',3000) ;//注意,此处“;”可加可不加</ ...

  6. C# Graphic 绘制圆、三角形、椭圆、图片

    在form和panel上可以绘制图形,线段,圆,文字,图形等等. 绘制代码必须放在OnPaint()函数里面,因为窗体刷新的时候,都会调用该函数,重新刷新所绘的图. 示例代码在Panel上绘制图形来简 ...

  7. SSAS-many 2 many one simple sample

    基本业务:一个事件发生后,影响到多个国家,这个事件也会被定一个事件类型(这里简化为type1,2,3),处理这个事件花费多长时间. 我们的事实表就记录这个事情,相对应的我们设计两个维表,一个是国家,一 ...

  8. 深度优先搜索 codevs 1031 质数环

    codevs 1031 质数环  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold   题目描述 Description 一个大小为N(N<=17)的质数环是 ...

  9. POJ 1984 Navigation Nightmare

    并查集,给n个点和m条边,每条边有方向和长度,再给q个询问,第i个询问查询两个点之间在Ti时刻时的曼哈顿距离(能连通则输出曼哈顿距离,否则输出-1) 这题跟Corporative Network 有点 ...

  10. Hibernate之Query接口的uniqueResult()方法

    如果查询返回多个值用list()方法 public void testQuery(){ Configuration config = new Configuration().configure(); ...