EF 基本数据过滤
没猜错的话, 你们一定会和一大堆查询条件过不去, 重复的写,反复的写, 写到山崩地裂.
今天看了园友的文字:
实体框架高级应用之动态过滤 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 基本数据过滤的更多相关文章
- asp.net MVC EF Where 过滤条件怎么写
做.Net开发的肯定都知道.Net Sql语句有个SqlParameter 一般用来做过滤判断逻辑写,那么到了EF 了还有这样的写法嘛?答案肯定是有的了,这里我只是把最粗糙和简单的写法罗列一些,具体封 ...
- EF架构~过滤导航属性等,拼接SQL字符串
拼接T-SQL串,并使它具有通用性 好处:与服务器建立一次连接,给服务器发一条SQL命令,即可实现 代码如下: 1 /// <summary> 2 /// 构建Insert语句串 3 // ...
- .NET深入实战系列--EF到底怎么写过滤条件
本文唯一访问地址:http://www.cnblogs.com/yubaolee/p/DynamicLinq.html 对于系统开发来说,按不同字段进行过滤查询是一种常见的需求.在EF中通常的做法是: ...
- .NET深入实战系列--EF到底怎么写过滤条件(转)
原文来自:http://www.cnblogs.com/yubaolee/p/DynamicLinq.html 对于系统开发来说,按不同字段进行过滤查询是一种常见的需求.在EF中通常的做法是: /// ...
- Linux如何查看进程是否存活
ps -ef | grep nginx ps -ef | grep(过滤) 进程名字
- Shell【常用知识总结】
一.常用知识总结 1.特殊变量($0,@,#,*,?) $0:当前脚本的文件名. $n:n是一个数字,表示第几个参数. $#:传递给脚本或函数的参数个数. $*:传递给脚本或函数的所有参数.当被双引号 ...
- %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 ...
- EF联合查询,如何设置条件过滤从表数据
最近在使用EF进行联合查询过程中,遇到了一件不开心的事情. 已禁用懒加载 var post = await _repository.GetMyPostById(blogId, postId).AsNo ...
- 在ASP.NET Core中通过EF Core实现一个简单的全局过滤查询
前言 不知道大家是否和我有同样的问题: 一般在数据库的设计阶段,会制定一些默认的规则,其中有一条硬性规定就是一定不要对任何表中的数据执行delete硬删除操作,因为每条数据对我们来说都是有用的,并且是 ...
随机推荐
- MyEclipse10 离线图文安装SVN插件教程
一.下载SVN插件subclipse 1.下载 下载地址:http://subclipse.tigris.org/servlets/ProjectDocumentList?folderID=2240 ...
- STM32启动文件选择说明
图1. STM32F10xxx标准外设库体系结构先说这个问题,大家都知道,我们在选择使用哪些外围的的时候,是去更改从官方模版中拷贝过来的stm32f10x_conf.h文件的27-48行,把我们要用的 ...
- ELK 信息统计分析-2
Range 按数值类型的字段聚合统计 { "query": { "match_all": {} }, "aggs": { "ter ...
- memcpy函数
实现1:<高质量c++,c编程指南> void *mymemcpy(void *dst,const void *src,size_t num) { assert((dst!=NULL)&a ...
- UEditor For ASP.Net Core Use Qiniu
UEditor For ASP.Net Core Use Qiniu 此项目为UEditor提供文件管理; 后端服务使用 ASP.Net Core; 使用七牛提供的云存储; 项目地址 https:// ...
- noip2008普及组4题题解-rLq
(啊啊啊终于补到了今天的作业了) 本题地址:http://www.luogu.org/problem/show?pid=1058 题目描述 小渊是个聪明的孩子,他经常会给周围的小朋友们将写自己认为有趣 ...
- Rem实现自适应初体验
第一次做移动端的页面,遇到的第一个问题就是移动端的轮播图.其实轮播图的插件有很多,但是完全满足需求的并不容易找. 需求: 1.实现基本的触屏轮播图效果 2.传入非标准比例的图片,可以自动平铺(有时候图 ...
- HDU 5084 HeHe --找规律
题意: 给出矩阵M,求M*M矩阵的r行c列的数,每个查询跟前一个查询的结果有关. 解法: 观察该矩阵得知,令ans = M*M,则 ans[x][y] = (n-1-x行的每个值)*(n-1+y列的每 ...
- ZOJ 3820 Building Fire Stations 求中点+树的直径+BFS
题意:给一棵树,要求找出两个点,使得所有点到这两个点中距离与自己较近的一个点的距离的最大值(所有点的结果取最大的值,即最远距离)最小. 意思应该都能明白. 解法:考虑将这棵树摆直如下: 那么我们可以把 ...
- UVALive 5966 Blade and Sword -- 搜索(中等题)
题意:给一幅地图,P为起点,D为终点,'*'为传送阵,到达传送阵可以传到任意一个其他的传送阵,传到以后可以正常走或者再传回来,问P->D最短步数. 分析:这题一定要细心,分析要到位才能搞定,错一 ...