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硬删除操作,因为每条数据对我们来说都是有用的,并且是 ...
随机推荐
- win10搭建代理服务器实现绕过校园网的共享限制--从入门到放弃
博主所在学校特别坑爹,校园网被电信一家垄断了,而且最恶心的还是电信要求一条网线只能供一台电脑上网,不许接路由器共享网络= =- (还有电信2M价格是380+每年,20m是500每年,而且网速都很慢= ...
- 在安装SqlServer2008时,有一项安装程序支持规则,为什么重新启动计算机那一项总是失败
1.运行 regedit 打开注册表编辑器. 2.依次展开HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager目录,找 ...
- hdu 4856 Tunnels (记忆化搜索)
Tunnels Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Su ...
- Linux Purify命令
一.简介 在C/C++的软件开发中,没有任何一种工具可以让你的应用程序避免引入内存问题,但是我们可以使用诸如Purify这样的工具对已经做好了的程序进行内存问题的检查.Purify的强大之处是可以找到 ...
- HTML5与触摸界面
习惯了开发典型的面向电脑端浏览器的网站在开发手机端网站或者移动App的时候面对很多新的问题,这些新的问题,在我看来或多或少会给浏览者在使用网站或App的时候带来不好的用户体验,对于一个产品级应用,用户 ...
- 边工作边刷题:70天一遍leetcode: day 71
Longest Substring with At Most Two Distinct Characters # Given a string, find the length of the long ...
- POJ 2001 Shortest Prefix
字典树基本题. 代码: #include <iostream> #include <cstdio> #include <cstring> #include < ...
- CSU 1060 Nearest Sequence
题意:求三个序列的最长公共子序列. 思路:一开始以为只要求出前两个的LCS,然后和第三个再求一遍LCS就是答案了.但是样例就对我进行啪啪啪打脸了.实际上就跟两个序列的差不多,换成三维的就行了. 代码: ...
- uGUI练习(四) Light UI
练习目标 在我之前的文章 Unity 2D Sprite Lighting ,讲到在2D Sprite中可以使用灯光,非常高兴的是,在Unity的新UI系统中我们也可以使用灯光 步骤 1.创建一个Pa ...
- java 21 - 6 字符缓冲流的特殊方法以及该方法高效复制文件
字符缓冲流的特殊方法: A.BufferedWriter: public void newLine():根据系统来决定换行符 private static void write() throws IO ...