简化NHibernate查询并分页

    最近公司在做一款OA的二次开发,是基于 J2EE 架构的 采用的 Spirng3 +Struts2+Hibernate3 UI 采用的EXTJS3。这款产品的框架设计的比较好,这几天正在研究。其中hibernate查询采用的通用方法,进行集中的查询字段收集、创建Criteria、查询数据。

    首先介绍一下实现思路。

    定义一个QueryFilter对象,然后在构造中接受一个HttpServletRequest对象,QueryFilter对HttpServletRequest中的 查询参数进行遍历,找到符合约定的参数时,对参数进行分析,并封装成hibernate的criteria对象,再交给service,service再交给dao,进由hibernate进行数据查询。

以下是大致的方法签名和调用

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中查询时候的代码

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#代码

 //-----------------动态创建 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 语句结束--------------------

项目结构如下,东西不多

image

具体代码如下

Filter.cs

/* ***********************************************
 * 作者 :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
             *   以上三个查询条件将被翻译为 (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

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

/* ***********************************************
 * 作者 :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,只要封装到通用的数据访问类中,大多数查询都不需要进行硬编码。

以下是我的简单的通用数据访问类

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) 
           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 : queryFilter.DataLimit)) + 1;
            dataPage.PageSize = queryFilter.DataLimit;
            dataPage.DateCount = count;
            Tension.NHibernate.NHibernateSessionFactory.CloseSession();
        }
    }
}

代码有点凌乱,以上只是扩展了GenericDAL<T> 因为这部分代码已经是封装好的DLL,所以没放源代码里。

页面上条用业务层查询数据返回结果只需如下

 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>() 
               { success = true, totalCount = datapage.DateCount, data = datapage.Result }.ToJson());
 
 

是不是觉得很方便?

刚刚用EXTJS 做的一个 demo

image

文章最下面有全部源码以及demo 的下载地址

点我下载Demo

汤晓华 QQ 1881597 MSN tension1990@hotmail.com

2011 05 16

posted @ 2011-05-16 22:30  tandly  阅读(3738)  评论(5编辑  收藏  举报