前言  

  不少公司用的是ADO.NET的访问方式,估计不少朋友对于sql的拼写真是没太多好感,在没有一个封装足够好的底层的项目(还需要考虑sql注入等问题),特别是经过许多人接手之后,代码那叫一个惨不忍睹,本文借助【通用查询设计思想】这篇文章的思想和基于ADO.NET进行通用查询设计。

  【通用查询设计思想】这篇文章是基于核心方法GenerateQueryExpression来生成表达式的,基于这个思想我们重新写个方法拼装成类似sql中的where条件

      /// <summary>
/// 生成查询条件
/// </summary>
/// <typeparam name="TEntity">要查询的实体类型</typeparam>
public static string GenerateQueryCriterion<TEntity>(this IQuery<TEntity> query) where TEntity : class
{
var criterion = " where 1 = 1 ";
if (query == null) return criterion; var condition = " and ";
var returnStr = string.Empty;
var queryType = query.GetType(); foreach (PropertyInfo property in queryType.GetProperties())
{
var value = property.GetValue(query);
if (null == value)
continue; if (value is string)
{
var str = ((string)value).Trim();
value = string.IsNullOrEmpty(str) ? null : str;
} //针对QueryMode特性获取我们指定要查询的路径
foreach (var attribute in property.GetAttributes<QueryModeAttribute>())
{
var propertyPath = attribute.PropertyPath;
if (propertyPath == null)
propertyPath = property.Name; var conditionStr = CreateConditionString(value, propertyPath, attribute.Compare);
if (string.IsNullOrWhiteSpace(conditionStr))
continue;
returnStr += condition + conditionStr;
}
} return criterion + returnStr;
} /// <summary>
/// 生成sql条件
/// </summary>
/// <param name="value"></param>
/// <param name="propertyPath"></param>
/// <param name="compare"></param>
/// <returns></returns>
private static string CreateConditionString(object value, string propertyPath, QueryCompare compare)
{
switch (compare)
{
case QueryCompare.Equal:
return CreateEqualString(propertyPath, value);
case QueryCompare.GreaterThanOrEqual:
return CreateGreaterThanOrEqualString(propertyPath, value);
case QueryCompare.LessThanOrEqual:
return CreateLessThanOrEqualString(propertyPath, value);
case QueryCompare.Like:
return CreateLikeString(propertyPath, value);
default:
return null;
}
} /// <summary>
/// 生成sql的等于条件
/// </summary>
/// <param name="propertyPath"></param>
/// <param name="value"></param>
/// <returns></returns>
private static string CreateEqualString(string propertyPath, object value)
{
if (value == null) return string.Empty; if (value is string)
{
return propertyPath + "='" + value + "'";
} if (value is bool)
{
if (value.ToString() == "False")
return propertyPath + "=0";
return propertyPath + "=1";
} return propertyPath + "=" + value;
}

  方法返回的就是我们常见的“ 1 = 1 and System='A' ” 这样的查询条件,其他的类似 大于,小于,like这些条件,相信以朋友们高超的智慧肯定不是什么难事:)

  

  为避免新朋友没看过【通用查询设计思想】这篇文章,个人把这次的变动的类罗列出来

  查询基类(保留表达式的方法,兼容同时使用Linq和ADO.NET的情况:))  

    public class Query<TEntity> : IQuery<TEntity> where TEntity: class
{
/// <summary>
/// 指定查询条件
/// </summary>
protected Expression<Func<TEntity, bool>> Predicate; /// <summary>
/// 创建一个新的 <see cref="Query{TEntity}"/>
/// </summary>
public Query()
{
} /// <summary>
/// 创建一个指定查询条件的<see cref="Query{TEntity}"/>
/// </summary>
/// <param name="predicate">指定的查询条件</param>
public Query(Expression<Func<TEntity, bool>> predicate)
{
Predicate = predicate;
} /// <summary>
/// 生成表达式
/// </summary>
/// <returns></returns>
public Expression<Func<TEntity, bool>> GenerateExpression()
{
return Predicate.And(this.GetQueryExpression());
} /// <summary>
/// 生成sql条件
/// </summary>
/// <returns></returns>
public string GenerateSqlCriterion()
{
return this.GenerateQueryCriterion();
}
}

  查询模式(保留PropertyPath给表达式,PropertyPath2不是数组,因为ADO.NET中应该不会涉及到导航属性

    public class QueryModeAttribute : Attribute
{
/// <summary>
/// 比较方式
/// </summary>
public QueryCompare Compare { get; set; } /// <summary>
/// 对应属性路径(Linq + Expression)
/// </summary>
public string[] PropertyPath { get; set; } /// <summary>
/// 对应属性路径(sql + ADO.NET)
/// </summary>
public string PropertyPath2 { get; set; } /// <summary>
/// 查询字段
/// </summary>
public QueryModeAttribute(params string[] propertyPath)
{
PropertyPath = propertyPath;
} /// <summary>
/// 查询字段
/// </summary>
public QueryModeAttribute(QueryCompare compare,params string[] propertyPath)
{
PropertyPath = propertyPath;
Compare = compare;
} /// <summary>
/// 查询字段
/// </summary>
public QueryModeAttribute(QueryCompare compare, string propertyPath2)
{
PropertyPath2 = propertyPath2;
Compare = compare;
}
}

  查询实体

    public class AccountQuery : PageQuery<Account>
{
/// <summary>
/// 姓名
/// </summary>
[Query(QueryCompare.Equal, nameof(Account.Name))]
public string Name { get; set; }
    
    //其他查询条件... }

  这样的话我们的之前的表达式写法成了下面这样

  public class AccountQuery : PageQuery<Account>
{
/// <summary>
/// 姓名
/// </summary>
[Query(QueryCompare.Equal, new[]{nameof(Account.Name)})]
public string Name { get; set; }
    
    //其他查询条件... }  

  来看一下我们完整的使用例子,很多情况下我们是需要分页和添加类似于Order By或者Group By这样的高级条件(本例子前端是使用layui,数据库是mysql)

      public PageResult<AccountDto> GetAccount(AccountQuery query)
{
var sql = @"select xx,xx,xx from user ";
var criterion = query.GenerateSqlCriterion(); sql += criterion; return return MySqlHelper.GetPageResult<AccountDto>(sql, null, query);
}   /// <summary>
/// 获取分页数据
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="cmdText"></param>
/// <param name="cmdParms"></param>
/// <param name="pageInfo"></param>
/// <param name="groupBy"></param>
/// <returns></returns>
  public static PageResult<T> GetPageResult<T>(string cmdText,
MySqlParameter[] cmdParms, PageInfo pageInfo, string groupBy = "") where T : class, new()
{
var result = new PageResult<T>
{
PageSize = pageInfo.PageSize,
PageIndex = pageInfo.PageIndex
};
//获取总数
var sqlCount = $"SELECT COUNT(*) FROM ({cmdText}) TableCount ";
var objCount = ExecuteScalar(CommandType.Text, sqlCount, cmdParms);
result.TotalCount = Convert.ToInt32(objCount); string pagingSql; //获取分页数据
if (string.IsNullOrWhiteSpace(groupBy))
{
pagingSql =
$"{cmdText} ORDER BY {pageInfo.Field ?? "id"} {pageInfo.Order ?? "desc"} " +
$"LIMIT {pageInfo.PageIndex}, {pageInfo.PageSize}";
}
else
{
//Group by
pagingSql =
$"{cmdText} GROUP BY {groupBy} ORDER BY {pageInfo.Field ?? "id"} {pageInfo.Order ?? "desc"}" +
$"LIMIT {pageInfo.PageIndex}, {pageInfo.PageSize}";
} var dt = ExecuteDataTable(CommandType.Text, pagingSql, cmdParms);
if (dt != null)
{
result.Data = dt.ToList<T>();
}
return result;
}

  当然,这只是我们的一般查询情况,实际情况中我们会遇到更复杂的sql,基于本文的中心主题,不再深入讨论其他场景。

  让我知道如果你有更好的想法!

  

通用查询设计思想(2)- 基于ADO.Net的设计的更多相关文章

  1. 平台+插件软件设计思想及基于COM的原型实现

    引言:我们已经习惯于一个人独立进行软件开发,每个人都使用自己的风格进行程序设计,但随着工程项目变大或者是对时间要求比较紧时,就需要几个人,十几个人,甚至是上百个人协作进行软件开发与设计,这时一个比较棘 ...

  2. Mysql高手系列 - 第27篇:mysql如何确保数据不丢失的?我们借鉴这种设计思想实现热点账户高并发设计及跨库转账问题

    Mysql系列的目标是:通过这个系列从入门到全面掌握一个高级开发所需要的全部技能. 欢迎大家加我微信itsoku一起交流java.算法.数据库相关技术. 这是Mysql系列第27篇. 本篇文章我们先来 ...

  3. FPGA设计思想与技巧(转载)

    题记:这个笔记不是特权同学自己整理的,特权同学只是对这个笔记做了一下完善,也忘了是从那DOWNLOAD来的,首先对整理者表示感谢.这些知识点确实都很实用,这些设计思想或者也可以说是经验吧,是很值得每一 ...

  4. FPGA/CPLD设计思想与技巧

    本文讨论的四种常用FPGA/CPLD设计思想与技巧:乒乓操作.串并转换.流水线操作.数据接口同步化,都是FPGA/CPLD逻辑设计的内在规律的体现,合理地采用这些设计思想能在FPGA/CPLD设计工作 ...

  5. 【学习笔记】【Design idea】一、Java异常的设计思想、性能相关、笔记

    1.前言: 异常.本该是多么优雅的东西,然而,得全靠自己在零散的信息中汇集. 学习笔记保持更新. 2.教材(参考资料) 其他 ①受检异常与非受检异常:https://www.cnblogs.com/j ...

  6. 基于 CSP 的设计思想和 OOP 设计思想的异同

    LinkerLin Go语言推崇的CSP编程模型和设计思想,并没有引起很多Go开发者包括Go标准库作者的重视.标准库的很多设计保留了很浓的OOP的味道.本篇Blog想比较下从设计的角度看,CSP和OO ...

  7. dapi 基于Django的轻量级测试平台一 设计思想

    GitHub:https://github.com/yjlch1016/dapi 一.项目命名: dapi:即Django+API测试的缩写 二.设计思想: 模拟性能测试工具JMeter的思路, 实现 ...

  8. 使用Unity3D的设计思想实现一个简单的C#赛车游戏场景

    最近看了看一个C#游戏开发的公开课,在该公开课中使用面向对象思想与Unity3D游戏开发思想结合的方式,对一个简单的赛车游戏场景进行了实现.原本在C#中很方便地就可以完成的一个小场景,使用Unity3 ...

  9. 掌握 Cinder 的设计思想 - 每天5分钟玩转 OpenStack(46)

    上一节介绍了 Cinder 的架构,这节讨论 Cinder 个组件如何协同工作及其设计思想. 从 volume 创建流程看 cinder-* 子服务如何协同工作 对于 Cinder 学习来说,Volu ...

随机推荐

  1. golang实现权重轮询调度算法

    package main import ( "fmt" "time" ) var slaveDns = map[int]map[string]interface ...

  2. SSH通过SSH代理连接到内网机器

    要解决的问题? 需要解决的问题:https://q.cnblogs.com/q/105319/ 简单来说就是本地机器通过一台公网机器SSH到公网机器后面的私网机器. 网络环境如下图:本地机器可访问代理 ...

  3. Java IO--字符流--InputStreamReader 和 OutputStreamWriter

    今天继续学习字符流的子类!!!! 先来熟悉一下适配器设计模式:(手写的,,嘿嘿) 因为据说InputStreamReader 和OutputStreamWriter采用了适配器模式(现在我还没能理解, ...

  4. MIP 技术进展月报:储存功能全新上线,MIP-Cache域名升级,校验更严谨

    集 ** 瞬时触达用户.高转化率.炫酷闪电标.优质展现形式 ** 等诸多特性为一体的 MIP 页面吸引了众多站点进行改造.为了更好地服务于广大站长,更快地倾听站长们的声音,MIP 技术团队特推出< ...

  5. BF-9000 BMC任务关键型应急通信系统

    一.系统简介 BF-9000 BMC任务关键型应急通信系统,凝聚北峰通信近30年专网通信与应急通信研发的经验,并结合用户实际需求和应用场景所打造. 整体设计思路是采用骨干网.前指网.分队战斗网三层组网 ...

  6. 深度揭秘腾讯云新一代企业级HTAP数据库TBase核心概念

    腾讯云PostgreSQL-XZ(PGXZ)经过公司内部多年业务的打磨,在2017年改名为TBase后,正式对外推出,目前已在政务.医疗.公安.消防.电信.金融等行业等行业的解决方案中大量应用.TBa ...

  7. SpringBoot之旅第四篇-web开发

    一.引言 有了自动配置,springboot使web开发变得简单,这个在springboot之旅中的第一篇中就有体现,实际的开发中当然不会这么简单,很多时候我们都需要自己去定制一些东西.web开发的东 ...

  8. C#判断字符串是不是英文或数字

    利用正则.   u4e00-u9fa5; //中文  ^[A-Za-z]+$  //英文字母 //截取冲击式样形状 public string SubStringForXingZhuang(strin ...

  9. 游戏AI之决策结构—有限状态机/行为树(2)

    目录 有限状态机 行为树 控制节点 条件节点 行为节点 装饰节点 总结 额外/细节/优化 游戏AI的决策部分是比较重要的部分,游戏程序的老前辈们留下了两种经过考验的用于AI决策的结构: 有限状态机 行 ...

  10. ASP .NET SignalR起步

    在网站开发中,时常需要使用消息推送功能,http协议是无状态连接,我们需要一个类似桌面程序中socket保持服务器和客户端连接的技术.signalr就是这样一个技术,他能保持网站页面和服务器的一个长连 ...