不少公司用的是 ADO.NET 的访问方式, 估计不少朋友对于 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 (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 += criterion + condition + conditionStr;
- }
- }
- return 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);
- 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 + "'";
- }
- 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 不再是数组, 因为 ADO.NET 中应该不会涉及到导航属性)
- public class QueryModeAttribute : Attribute
- {
- /// <summary>
- /// 比较方式
- /// </summary>
- public QueryCompare Compare { get; set; }
- /// <summary>
- /// 对应属性路径
- /// </summary>
- public string PropertyPath { get; set; }
- /// <summary>
- /// 查询字段
- /// </summary>
- public QueryAttribute(QueryCompare compare, string propertyPath)
- {
- PropertyPath = propertyPath;
- Compare = compare;
- }
- }
查询实体
- public class AccountQuery : PageQuery<Account>
- {
- /// <summary>
- /// 姓名
- /// </summary>
- [Query(QueryCompare.Equal, 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 MySqlHelper.GetPageResult<AccountDto>(sql, null, query.PageIndex, query.PageSize, query.Field, query.Order);
- }
- /// <summary>
- /// 获取分页数据
- /// </summary>
- /// <typeparam name="T"></typeparam>
- /// <param name="cmdText"></param>
- /// <param name="cmdParms"></param>
- /// <param name="pageIndex"></param>
- /// <param name="pageSize"></param>
- /// <param name="orderField"></param>
- /// <param name="sort"></param>
- /// <param name="groupBy"></param>
- /// <returns></returns>
- public static PageResult<T> GetPageResult<T>(string cmdText,
- MySqlParameter[] cmdParms, int pageIndex, int pageSize, string orderField ="id", string sort = "desc", string groupBy = "") where T : class, new()
- {
- var result = new PageResult<T>
- {
- PageSize = pageSize,
- PageIndex = 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 {orderField} {sort}" +
- $"LIMIT {(pageIndex - 1) * pageSize}, {pageSize}";
- }
- else
- {
- //Group by
- pagingSql =
- $"{cmdText} GROUP BY {groupBy} ORDER BY {orderField} {sort}" +
- $"LIMIT {(pageIndex - 1) * pageSize}, {pageSize}";
- }
- var dt = ExecuteDataTable(CommandType.Text, pagingSql, cmdParms);
- if (dt != null)
- {
- result.Data = dt.ToList<T>();
- }
- return result;
- }
当然, 这只是我们的一般查询情况, 实际情况中我们会遇到更复杂的 sql, 基于本文的中心主题, 不再深入讨论其他场景.
让我知道如果你有更好的想法!
来源: https://www.cnblogs.com/lex-wu/p/10486959.html