前言  

  不少公司用的是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. BZOJ_4378_[POI2015]Logistyka_树状数组

    BZOJ_4378_[POI2015]Logistyka_树状数组 Description 维护一个长度为n的序列,一开始都是0,支持以下两种操作: 1.U k a 将序列中第k个数修改为a. 2.Z ...

  2. mybatis 异常Result Maps collection does not contain value for java.lang.String

    Result Maps collection does not contain value for java.lang.String 以上是我报的错. 只要报Result Maps collectio ...

  3. mysql循环插入数据

    实验中经常会遇到需要多条数据的情况就想到了用SQL语句循环生成数据 DROP PROCEDURE if EXISTS test_insert; DELIMITER ;; CREATE PROCEDUR ...

  4. [Active Learning] Multi-Criteria-based Active Learning

    目录 1 Informativeness 2 Representativeness 3 Diversity 3.1 Global consideration 3.2 Local considerati ...

  5. 领域驱动设计学习之路—DDD的原则与实践

    本文是我学习Scott Millett & Nick Tune编著的<领域驱动设计模式.原理与实践>一书的学习笔记,一共会分为4个部分如下,此文为第1部分: ① 领域驱动设计的原则 ...

  6. 你真的了解ASP.NET Core 部署模型吗?

    ----------------------------   以下内容针对 ASP.NET Core2.1,2.2出现IIS进程内寄宿 暂不展开讨论-------------------------- ...

  7. 『Lucas定理以及拓展Lucas』

    Lucas定理 在『组合数学基础』中,我们已经提出了\(Lucas\)定理,并给出了\(Lucas\)定理的证明,本文仅将简单回顾,并给出代码. \(Lucas\)定理:当\(p\)为质数时,\(C_ ...

  8. [深度应用]·实战掌握Dlib人脸识别开发教程

    [深度应用]·实战掌握Dlib人脸识别开发教程 个人网站--> http://www.yansongsong.cn/ 项目GitHub地址--> https://github.com/xi ...

  9. Android Gradle defaultConfig详解及实用技巧

    实际项目中,都会应用Android Gradle Plugin,根据实际中的项目模块的职责,可以具体应用如下四种插件类型. 1,apply plugin: 'com.android.applicati ...

  10. 包装类及 LeetCode 每日一题

    1.包装类与创建对象 Java 为8大数据类型都提供了相应的包装类,并提供属性和方法,更方便的操作基本数据类型.包装类位于java.lang包中. 对于这几种类型的基本数据,都有相似的方法实现基本数据 ...