简化NHibernate查询并分页
最近公司在做一款OA的二次开发,是基于 J2EE 架构的 采用的 Spirng3 +Struts2+Hibernate3 UI 采用的EXTJS3。这款产品的框架设计的比较好,这几天正在研究。其中hibernate查询采用的通用方法,进行集中的查询字段收集、创建Criteria、查询数据。
首先介绍一下实现思路。
定义一个QueryFilter对象,然后在构造中接受一个HttpServletRequest对象,QueryFilter对HttpServletRequest中的 查询参数进行遍历,找到符合约定的参数时,对参数进行分析,并封装成hibernate的criteria对象,再交给service,service再交给dao,进由hibernate进行数据查询。
以下是大致的方法签名和调用
1 2 | QueryFilter filter = new QueryFilter(HttpServletRequest request); List<BookType> list = bookTypeService.getAll(filter); |
过滤条件的名称必须符合如下规则:Q_firstName_S_EQ ,其中Q标识该查询参数是一个QueryFilter能识别的字符,firstName 表示待查询的属性名称(可以是外键对象的属性),S 表示为 String 类型,EQ 表示 equals ,当然 S 位置 和 EQ 位置还有其它约定的表达式。通过这种方式,在进行数据查询时,不需要进行硬编码,只需要在html代码,或者JavaScript进行 Ajax 查询时,指定符合要求的querystring 即可。
以下是extjs中查询时候的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | return new Ext.Panel({ id : 'BookTypeView' , title : '档案类别列表' , iconCls : 'menu-book-type' , autoScroll : true , items : [ new Ext.FormPanel({ height : 35, frame : true , id : 'BookTypeSearchForm' , layout : 'column' , defaults : { xtype : 'label' }, items : [{ text : '请输入查询条件:' }, { text : '档案类别' }, { xtype : 'textfield' , name : 'Q_typeName_S_LK' }, { xtype : 'button' , text : '查询' , iconCls : 'search' , handler : function () { search(); } }, { xtype : 'button' , text : '取消查询条件' , iconCls : 'btn-del' , handler : function () { var searchPanel = Ext.getCmp( 'BookTypeSearchForm' ); var grid = Ext.getCmp( 'BookTypeGrid' ); searchPanel.items.get(2).setValue( "" ); search(); } }] }), this .setup()] }); }; |
为了使我以后更懒的工作,周末花了点时间写了一个C#&Asp.Net的实现(其实我主要是做.NET平台的,Java我真的不想做)。大致上还是采用的这款OA中实现的思路。但是发现一个问题,它的QueryFilter只能够进行与查询,也就是各个查询条件是用AND相连接的,无法进行OR查询,或者 多个条件单独与或 在 与 另外一个条件与或 , 比如 (a = 1 and b = 2) or c = false ,所以我简单实现了 多组查询的功能。查询字符串的约定规则模仿Q_firstName_S_EQ 稍微做了一些改变 ,例如:Q_firstName_S_EQ_AND_0_1 , 其中 Q_firstName_S_EQ 部分是完全一致的。
AND 为条件聚合方式,可以是 AND 或者 OR ,
0 必须为数字,表示查询条件的组 , 相同的组ID将被归并成一个查询条件
1 必须为数字,表示查询条件组中成员的顺序
查询条件组 与 组成员都将按照顺序产生 HQL 语句。
可能光从字面上理解有点误会,笔者表达的也却有欠缺。
打个比方:
Q_firstName_S_LK_AND_0_1,
Q_lastName_S_LK_OR_0_2,
Q_age_I_>_AND_1_1,
其中 Q_firstName_S_LK_AND_0_1,Q_lastName_S_LK_OR_0_2 属于同一组 将产生 (firstName like :firstName and lastName like :firstName )
Q_age_I_>_AND_1_1 单独一组 将产生 (age = :age)
两组合并为一句HQL语句为(firstName like :firstName and lastName like :firstName) or (age = :age) 。
那么 and 和 or 又是按照什么规则连续的呢?
组我的规则是,同一组的查询条件的聚合类型作用于下一个查询条件,前一组的最后一个成员的聚合方式作用于下一组,又很拗口…………
对照一下
(firstName like :firstName and lastName like :firstName) or (age = :age) 。
Q_firstName_S_LK_AND_0_1,Q_lastName_S_LK_OR_0_2,Q_age_I_>_AND_1_1 ,??? 最后一个AND 呢?只要当前查询条件是最后一个,AND 或者 OR 将被忽略。很难设计啊…
以下是创建HQL的部分C#代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | //-----------------动态创建 where 语句开始-------------------- string lastCT = "" ; var lastGroup = queryable.LastOrDefault(); foreach ( var item in queryable) { var last = item.LastOrDefault(); hqlSb.Append( " (" ); foreach ( var _item in item) { lastCT = _item.ConnectionType; hqlSb.Append( " t." ); hqlSb.Append(_item.CreateHqlPart()); if (!last.Equals(_item)) { hqlSb.Append( " " + lastCT + " " ); } } hqlSb.Append( ") " ); if (lastGroup.Key != item.Key) { hqlSb.Append(lastCT); } } //-----------------动态创建 where 语句结束-------------------- |
项目结构如下,东西不多
具体代码如下
Filter.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | /* *********************************************** * 作者 :tension 任何转载请务必保留此头部信息 版权所有 盗版必究 * Email:tension1990@hotmail.com * QQ:1881597 * 描述 : * 创建时间:2011/5/15 * 修改历史: * ***********************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using NHibernate; using NHibernate.Criterion; namespace Tension.NHibernate.Query { /// <summary> /// 过滤条件 /// </summary> public class Filter { #region 字段属性 public string ParamName { get ; set ; } /// <summary> /// 条件中的字段名称 /// </summary> public string PropertyName { get ; set ; } /// <summary> /// 条件中的字段值 /// </summary> public object PropertyValue { get ; set ; } /// <summary> /// HQL占位作用的字段名 区别在于 弱 是关联对象查询 则去处 . 号 如 PropertyName=Group.Name 则PlaceholderPropertyName=GroupName /// NHibernate 在分析HQL时 若占位符存在 . 会报异常 /// </summary> public string PlaceholderPropertyName { get ; set ; } /// <summary> /// 字段数据类型 /// </summary> public string PropertyType { get ; set ; } /// <summary> /// 条件类型 /// </summary> public string Operation { get ; set ; } /// <summary> /// 条件组连接类型 /// </summary> public string ConnectionType { get ; set ; } /// <summary> /// 条件组 /// </summary> public int Group { get ; set ; } /// <summary> /// 组成员索引 /// </summary> public int Index { get ; set ; } private int pindex = 0; /// <summary> /// 参数索引位置 /// </summary> public int PIndex { get { return pindex; } set { PlaceholderPropertyName = PropertyName.Replace( "." , "" ) + value; pindex = value; } } /// <summary> /// 参数全名 /// </summary> private string paramName; /// <summary> /// 不需要添加到IQuery 的参数集合 /// </summary> public bool NoAdd { get ; set ; } /// <summary> /// 支持的数据类型的简写 /// </summary> private string [] PropertyTypes = new string [] { "S" , "D" , "DEC" , "FT" , "I" , "IS" , "IB" , "ST" , "L" , "B" , "ARR" }; /// <summary> /// 支持的比较运算符 /// </summary> private string [] Operations = new string [] { "EQ" , "LT" , "<" , "GT" , ">" , "LE" , "<=" , "GE" , ">=" , "LK" , "LIKE" , "LFK" , "LIKE%" , "RHK" , "%LIKE" , "NULL" , "NOTNULL" , "IN" , "BT" }; #endregion #region 构造 /// <summary> /// 空构造 /// </summary> public Filter() { } /// <summary> /// /// </summary> /// <param name="paramName"></param> /// <param name="paramVal"></param> public Filter( string paramName, object propertyValue) { /** * * Q_propertyName_S_EQ_AND_0_1 * * 使用 _ 分割 * 0 位置 Q 是判断字符串是否为查询字符串 * 1 位置 Q_propertyName_S_EQ_AND_0_1 是字段名称 * 2 位置 S 是字段类型 * * 该位置的其他值有: * S= string D=DateTime,DEC= decimal ,FT= float ,I=Int32,IS=Int16,IB=Int64,ST= short ,L=Long,B= bool * * 3 位置 EQ 是条件类型 比如EQ代表等于 * 4 位置 AND 是 AND 或者 OR 查询组的最后一个查询表达式的 AND 或者 OR 将被忽略 * 5 位置 0 代表的是条件组 * 6 位置 1 代表条件组中条件的顺序 * * 查询组的组后一个查询成员的 4 位置 值在当前查询组中不起作用 * 若存在下一查询组 则查询组后一个查询成员的的 4 位置 值作为与下一查询组的连接符 * * 例如 * Q_propertyName0_S_EQ_AND_0_1 * Q_propertyName1_S_EQ_AND_1_1 * Q_propertyName2_S_EQ_AND_2_1 * 以上三个查询条件将被翻译为 (propertyName0 = :propertyName0) and (propertyName1 = :propertyName1) and (propertyName2 = :propertyName2) * * * Q_propertyName0_S_EQ_AND_0_1 * Q_propertyName1_S_EQ_OR_1_1 * Q_propertyName2_S_EQ_AND_1_2 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | * 以上三个查询条件将被翻译为 (propertyName0 = :propertyName0) and (propertyName1 = :propertyName1 or propertyName2 = :propertyName2) * * Q_propertyName0_S_EQ_AND_0_1 * Q_propertyName1_S_EQ_OR_0_2 * Q_propertyName2_S_EQ_AND_1_1 * Q_propertyName3_S_EQ_AND_1_2 * 以上4个查询条件将被翻译为 (propertyName0 = :propertyName0 and propertyName1 = :propertyName1) or (propertyName2= :propertyName2 and or propertyName3= :propertyName3) * * * * * */ ParamName = paramName; if (paramName.IndexOf( "Q_" ) != 0) { throw new ArgumentNullException( "查询条件[paramName]不是合法的查询语句!必须以 Q_ 开头" ); } this .paramName = paramName; this .PropertyValue = propertyValue; //执行解析 Analysis(); } #endregion #region 方法 /// <summary> /// 解析 /// </summary> private void Analysis() { if (paramName == null ) { throw new ArgumentNullException( "查询条件[paramName]不能为空!" ); } string [] param_s = paramName.Split( '_' ); if (param_s.Length < 7) { throw new ArgumentException( string .Format( "\n\n 查询条件: {0} 不符合规范,请按照 如下标准:Q_propertyName0_S_EQ_AND_0_0\n" , paramName)); } PropertyName = param_s[1]; //除去关联对象查询时的 . 例如 Group.Name PlaceholderPropertyName = PropertyName.Replace( "." , "" ); //字段类别的简写 PropertyType = param_s[2].ToUpper(); if (!PropertyTypes.Contains(PropertyType)) { throw new ArgumentException( "参数字符串中[2]位置(字段类别的简写) 必须为:" + string .Join( "," , PropertyTypes)); } Operation = param_s[3].ToUpper(); if (!Operations.Contains(Operation)) { throw new ArgumentException( "参数字符串中[3]位置(支持的比较运算符) 必须为:" + string .Join( "," , Operations)); } ConnectionType = param_s[4].ToLower(); if (ConnectionType != "and" && ConnectionType != "or" ) { throw new ArgumentException( "参数字符串中[4]位置(查询条件的连接方式) 必须为 AND 或者 OR" ); } try { Group = int .Parse(param_s[5]); } catch (Exception) { throw new ArgumentException( "参数字符串中[5]位置(代表所属查询组) 必须为整数数字" ); } try { Index = int .Parse(param_s[6]); } catch (Exception) { throw new ArgumentException( "参数字符串中[6]位置(代表查询组成员排序) 必须为整数数字" ); } //处理like 是的 value if ( "LK" == Operation || "LIKE" == Operation) { PropertyValue = string .Format( "%{0}%" , PropertyValue); } else if ( "LFK" == Operation || "LIKE%" == Operation) { PropertyValue = string .Format( "{0}%" , PropertyValue); } else if ( "RHK" == Operation || "%LIKE" == Operation) { PropertyValue = string .Format( "%{0}" , PropertyValue); } //处理 NULL 或者 NOTNULL 查询设置该filter 是否要添加参数到查询 else if ( "NULL" == Operation) { NoAdd = true ; } else if ( "NOTNULL" == Operation) { NoAdd = true ; } } /// <summary> /// 产生 HQL 的 where 部分条件字符串 /// </summary> /// <returns></returns> public string CreateHqlPart() { if ( "LT" == Operation || "<" == Operation) { return string .Format( "{0} < :{1} " , PropertyName, PlaceholderPropertyName); } else if ( "GT" == Operation || ">" == Operation) { return string .Format( "{0} > :{1} " , PropertyName, PlaceholderPropertyName); } else if ( "LE" == Operation || "<=" == Operation) { return string .Format( "{0} <= :{1} " , PropertyName, PlaceholderPropertyName); } else if ( "GE" == Operation || ">=" == Operation) { return string .Format( "{0} >= {1} " , PropertyName, PlaceholderPropertyName); } else if ( "LK" == Operation || "LIKE" == Operation) { return string .Format( "{0} like :{1} " , PropertyName, PlaceholderPropertyName); } else if ( "LFK" == Operation || "LIKE%" == Operation) { return string .Format( "{0} like :{1} " , PropertyName, PlaceholderPropertyName); } else if ( "RHK" == Operation || "%LIKE" == Operation) { return string .Format( "{0} like :{1} " , PropertyName, PlaceholderPropertyName); } else if ( "NULL" == Operation) { return string .Format( "{0} is null " , PropertyName); } else if ( "NOTNULL" == Operation) { return string .Format( "{0} is not null " , PropertyName); } else if ( "IN" == Operation) { return string .Format( "{0} in (:{1}) " , PropertyName, PlaceholderPropertyName); } else if ( "BT" == Operation) { return string .Format( "{0} between (:{1}) and (:{2})" , PropertyName, PlaceholderPropertyName + "_0" , PlaceholderPropertyName + "_1" ); } else { return string .Format( "{0} = :{1} " , PropertyName, PlaceholderPropertyName); } } #endregion } } |
QueryFilter.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using NHibernate; using System.Collections; /* *********************************************** * 作者 :tension 任何转载请务必保留此头部信息 版权所有 盗版必究 * Email:tension1990@hotmail.com * QQ:1881597 * 描述 : * 创建时间:2011/5/15 * 修改历史: * ***********************************************/ namespace Tension.NHibernate.Query { /// <summary> /// 查询过滤器 /// </summary> public class QueryFilter<T> where T : class { #region 字段属性 /// <summary> /// 数据起始位置 /// </summary> public int DataStart { get ; set ; } /// <summary> /// 每页显示的条数 /// </summary> public int DataLimit { get ; set ; } ///// <summary> ///// 数据总数 ///// </summary> //public int DataCount { get; set; } /// <summary> /// 排序字段 /// </summary> public string Sort { get ; set ; } private string dir = "asc" ; /// <summary> /// asc desc /// </summary> public string Dir { get { return dir; } set { dir = value; } } /// <summary> /// 过滤条件集合 /// </summary> private IList<Filter> filters = new List<Filter>(); /// <summary> /// 过滤条件缓存 /// </summary> private static Dictionary< string , string > QueryHqlCache; /// <summary> /// 当前的HQL /// </summary> public string CurrentHQL { get ; set ; } /// <summary> /// 计算数据条数的HQL /// </summary> public string CountHQL { get ; set ; } #endregion #region 构造 /// <summary> /// 静态构造 /// </summary> static QueryFilter() { QueryHqlCache = new Dictionary< string , string >(); } #endregion #region 方法 /// <summary> /// 增加过滤条件 类型 Filter /// </summary> /// <param name="filter"></param> public void AddFilter(Filter filter) { if (filter.PropertyValue.ToString() != "NOTADD" ) { filter.PIndex = filters.Count + 1; filters.Add(filter); } } /// <summary> /// 增加过滤条件 类型 string /// </summary> /// <param name="filter"></param> public void AddFilter( string paramName, object obj) { AddFilter( new Filter(paramName, obj)); } /// <summary> /// 创建查询数据条数的IQuery /// </summary> /// <param name="session"></param> /// <returns></returns> public IQuery CreateCountQuery(ISession session) { if ( string .IsNullOrEmpty(CountHQL)) { InitHQL(); } IQuery query = session.CreateQuery(CountHQL); AddParameters(query); return query; } /// <summary> /// 创建IQuery对象 /// </summary> /// <param name="session"></param> /// <returns></returns> public IQuery CreateQuery(ISession session) { InitHQL(); if (! string .IsNullOrEmpty(Sort)) { CurrentHQL += string .Format( " order by {0} {1}" , Sort, Dir); } IQuery query = session.CreateQuery(CurrentHQL); if (DataLimit > 0) { query.SetMaxResults(DataLimit). SetFirstResult(DataStart); } AddParameters(query); return query; } /// <summary> /// 初始化HQL 该方法同事初始化 CurrentHQL 与 CountHQL /// </summary> private void InitHQL() { CurrentHQL = BuildHql(); CountHQL = CurrentHQL.Replace( "from" , "select count(*) from" ); } /// <summary> /// 向 IQuery 添加参数 /// </summary> /// <param name="query"></param> private void AddParameters(IQuery query) { foreach ( var item in filters) { if (!item.NoAdd && item.PropertyType == "ARR" ) query.SetParameterList(item.PlaceholderPropertyName, item.PropertyValue as object []); else if (!item.NoAdd) { //query.SetParameter(item.PlaceholderPropertyName, item.PropertyValue); if (item.Operation == "BT" ) { string [] valarr = item.PropertyValue.ToString().Split( '_' ); query.SetParameter(item.PlaceholderPropertyName + "_0" , ValueConverter.Convert(item.PropertyType, valarr[0])); query.SetParameter(item.PlaceholderPropertyName + "_1" , ValueConverter.Convert(item.PropertyType, valarr[1])); } else { query.SetParameter(item.PlaceholderPropertyName, ValueConverter.Convert(item.PropertyType, item.PropertyValue)); } } } } /// <summary> /// 创建HQL /// </summary> /// <returns></returns> public string BuildHql() { string key = CreateQueryFilterKey(); if (QueryHqlCache.ContainsKey(key)) { return QueryHqlCache[key]; } else { string hqlStr = "" ; var queryable = GetSortedFilterGroup(); int groupCount = queryable.Count(); StringBuilder hqlSb = new StringBuilder( string .Format( "from {0} t" , typeof (T).Name)); if (groupCount != 0) { hqlSb.Append( " where " ); } //-----------------动态创建 where 语句开始-------------------- string lastCT = "" ; var lastGroup = queryable.LastOrDefault(); foreach ( var item in queryable) { var last = item.LastOrDefault(); hqlSb.Append( " (" ); foreach ( var _item in item) { lastCT = _item.ConnectionType; hqlSb.Append( " t." ); hqlSb.Append(_item.CreateHqlPart()); if (!last.Equals(_item)) { hqlSb.Append( " " + lastCT + " " ); } } hqlSb.Append( ") " ); if (lastGroup.Key != item.Key) { hqlSb.Append(lastCT); } } //-----------------动态创建 where 语句结束-------------------- if (!QueryHqlCache.ContainsKey(key)) { hqlStr = hqlSb.ToString(); QueryHqlCache[key] = hqlStr; } return hqlStr; } } /// <summary> /// 创建当前查询的 key 用于缓存查询 /// </summary> /// <returns></returns> private string CreateQueryFilterKey() { var queryable = GetSortedFilterGroup(); StringBuilder key = new StringBuilder(); foreach ( var item in queryable) { foreach ( var _item in item) { key.Append(_item.ParamName); key.Append( "&" ); } } return key.ToString(); } /// <summary> /// 获取排序并分组后的查询过滤条件 /// </summary> /// <returns></returns> private IOrderedEnumerable<IGrouping< int , Filter>> GetSortedFilterGroup() { var queryable = filters.Select(s => s).OrderBy(d => d.Index).GroupBy(f => f.Group).OrderBy(f => f.Key); return queryable; } #endregion } } |
ValueConverter.cs
/* ***********************************************
* 作者 :tension 任何转载请务必保留此头部信息 版权所有 盗版必究
* Email:tension1990@hotmail.com
* QQ:1881597
* 描述 :
* 创建时间:2011/5/15
* 修改历史:
* ***********************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Tension.NHibernate.Query
{
/// <summary>
/// 值转换器
/// </summary>
public class ValueConverter
{
#region 方法
/// <summary>
/// 转换到对应的类型
/// </summary>
/// <param name="type"></param>
/// <param name="obj"></param>
/// <returns></returns>
public static object Convert(string type, object obj)
{
string val = obj.ToString();
//type : S=string D=DateTime,DEC=decimal,FT=float,I=Int32,I16=Int16,I64=Int64,ST=short,L=Long,B=bool;A=object[]
//"S", "D", "DEC", "FT", "I", "IS", "IB", "ST", "L", "B","ARR"
switch (type)
{
case "S": //string
return val;
case "D": //DateTime
return DateTime.Parse(val);
case "DEC"://decimal
return decimal.Parse(val);
case "FT": //float
return float.Parse(val);
case "I":
return Int32.Parse(val);
case "IS":
return Int16.Parse(val);
case "IB":
return Int64.Parse(val);
case "ST":
return short.Parse(val);
case "L":
return long.Parse(val);
case "B":
if (val == "0")
return false;
if (val == "1")
{
return true;
}
return bool.Parse(val);
case "ARR":
return obj as object[];
default:
return type;
}
}
#endregion
}
}
WebQueryFilter.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | /* *********************************************** * 作者 :tension 任何转载请务必保留此头部信息 版权所有 盗版必究 * Email:tension1990@hotmail.com * QQ:1881597 * 描述 : * 创建时间:2011/5/15 * 修改历史: * ***********************************************/ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Web; namespace Tension.NHibernate.Query { /// <summary> /// 用于web方式的查询过滤器 实现自动注入查询条件 /// </summary> /// <typeparam name="T"></typeparam> public class WebQueryFilter<T> : QueryFilter<T> where T : class { private string sort_qs = "sort" ; private string dir_qs = "dir" ; private string start_qs = "start" ; private string limit_qs = "limit" ; #region 构造 public WebQueryFilter() : base () { } /// <summary> /// 自动封装Request.Params 中符合条件的查询参数 /// </summary> /// <param name="Request">HttpRequest</param> /// <param name="sort_qs">排序字段在 querystring 中的 名称 指 key </param> /// <param name="dir_qs">排序方式 querystring 中的 名称 指 key </param> /// <param name="start_qs">分页时数据起始位置 querystring 中的 名称 指 key </param> /// <param name="limit_qs">分页时每页的数据条数 querystring 中的 名称 指 key </param> public WebQueryFilter(HttpRequest Request, string sort_qs, string dir_qs, string start_qs, string limit_qs) { } /// <summary> /// 参数为 HttpRequest 自动封装Request.Params 中符合条件的查询参数 /// </summary> /// <param name="Request"></param> public WebQueryFilter(HttpRequest Request) { foreach ( var item in Request.Params.Keys) { if (item == null ) { continue ; } string key = item.ToString(); if (key.IndexOf( "Q_" ) == 0) { string [] values = Request.Params.GetValues(key); if (key.Split( '_' )[2].ToUpper() == "ARR" ) { base .AddFilter(key, Request.Params.GetValues(key)); } else { string val = Request.Params.Get(key); base .AddFilter(key, val); } } } string start = Request.Params.Get(start_qs) ?? "0" ; string limit = Request.Params.Get(limit_qs) ?? "max" ; if (limit != "max" ) { DataStart = int .Parse(start); DataLimit = int .Parse(limit); } string sort = Request.Params.Get(sort_qs); string dir = Request.Params.Get(dir_qs) ?? "asc" ; if (! string .IsNullOrEmpty(sort)) { Sort = sort; Dir = dir; } } #endregion } } |
简单介绍一下各个类的功能
Filter 主要是对 一个 查询条件进行封装 ,对表达式的解析,值的转换
ValueConverter 是通过约定好的数据类型的简写进行对应的转换
QueryFilter 是将一个查询请求中 所有的 查询条件(Filter) 进行 HQL 的转换,并同时具有Nhibernate 的 IQuery 对象的创建功能,同时通过该类可以进行 多条件查询、分页、排序等操作。
WebQueryFilter 继承自 QueryFilter 主要增加了 ASP.NET 环境下 对查询结果自动封装的功能。QueryFilter 不具有此能力,适用于手动指定查询条件的情况。
通过QueryFilter,只要封装到通用的数据访问类中,大多数查询都不需要进行硬编码。
以下是我的简单的通用数据访问类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | using System; using System.Collections.Generic; using System.Linq; using System.Text; using Tension.NHibernate; using Tension; using Tension.NHibernate.Query; using NHibernate; namespace Service { public static class Extension { public static void Query<T>( this GenericDAL<T> gd, DataPage<T> dataPage, QueryFilter<T> queryFilter) |
1 2 3 4 5 6 7 8 9 | where T : class { var session = Tension.NHibernate.NHibernateSessionFactory.GetSession(); IQuery query = queryFilter.CreateQuery(session); IQuery count_query = queryFilter.CreateCountQuery(session); object o = count_query.UniqueResult(); int count = int .Parse(o.ToString()); dataPage.Result = query.List<T>(); dataPage.PageIndex = (queryFilter.DataStart / (queryFilter.DataLimit == 0 |
1 2 3 4 5 6 7 | ? 1 : queryFilter.DataLimit)) + 1; dataPage.PageSize = queryFilter.DataLimit; dataPage.DateCount = count; Tension.NHibernate.NHibernateSessionFactory.CloseSession(); } } } |
代码有点凌乱,以上只是扩展了GenericDAL<T> 因为这部分代码已经是封装好的DLL,所以没放源代码里。
页面上条用业务层查询数据返回结果只需如下
1 2 3 4 5 | CustomerService Service = new CustomerService(); DataPage<Customer> datapage = new DataPage<Customer>(); var wqf = new WebQueryFilter<Customer>(Request); Service.Query<Customer>(datapage, wqf); Response.Write( new ExtJsGridData<Customer>() |
1 | { success = true , totalCount = datapage.DateCount, data = datapage.Result }.ToJson()); |
1 | |
1 | |
是不是觉得很方便?
刚刚用EXTJS 做的一个 demo
文章最下面有全部源码以及demo 的下载地址
汤晓华 QQ 1881597 MSN tension1990@hotmail.com
2011 05 16
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· [AI/GPT/综述] AI Agent的设计模式综述