标题已指出本文要说的三件事,首先是主角jqgrid,将应用在自定义列表中,重点介绍如何实现高级查询。
使用jqgrid实现自定义列表分为两大步骤,首先是要根据业务完成jqgrid的对象定义,即列表的描述配置;再就是服务端加载数据json对象。为实现更丰富条件的数据展示,jqgrid内置了高级检索的功能,可以自定义条件、自定义and、or的规则来查询数据,如图:
查询功能很强大,但问题也明显,后台如何识别这些条件?以下是我使用的方法:
1、定义高级查询的对象,通过json转换为对象,一来后台能够好进行参数处理,二来强制性的规则更安全,有规则成方圆。
2、为了完成where条件的转换,对高级查询对象进行解析,处理成可执行的sql where查询条件。
3、在实现上面功能之前,应先完成列表数据字段的规则定义,只有有效的字段才能进行查询。
以下是查询对象的定义:
/// <summary>
/// jqgrid高级查询json反序列化对象
/// </summary>
[Serializable]
public class ComplexFilters
{
/// <summary>
/// 查询条件AND、OR
/// </summary>
public string groupOp { get; set; } /// <summary>
/// 查询字段
/// </summary>
public List<FilterItem> rules { get; set; } /// <summary>
/// 嵌套查询
/// </summary>
public List<ComplexFilters> groups { get; set; }
} /// <summary>
/// jqgrid高级查询字段明细
/// </summary>
[Serializable]
public class FilterItem
{
/// <summary>
/// 字段名称
/// </summary>
public string field { get; set; } /// <summary>
/// 查询条件
/// </summary>
public string op { get; set; } /// <summary>
/// 关键字
/// </summary>
public string data { get; set; }
}
以下是查询规则的解析:
/// <summary>
/// 高级查询,通过grid传入的filter参数进行解析
/// </summary>
public class GridComplexFilter
{
#region 初始化查询对象 /// <summary>
/// 高级查询对象
/// </summary>
public Util.WebControl.ComplexFilters _filterObj { get; set; } /// <summary>
/// 字段定义
/// </summary>
public Service.Grid.Base_QueryFieldRORL _baseFiles { get; set; } /// <summary>
/// 原始高级查询字符串
/// </summary>
public string _filterStr { get; set; } /// <summary>
/// 初始化对象
/// </summary>
/// <param name="f">grid传入filter参数</param>
/// <param name="b">查询字段对象集</param>
public GridComplexFilter(string f, Service.Grid.Base_QueryFieldRORL b)
{
if (!string.IsNullOrEmpty(f) && b != null)
{
this._filterObj = Json.ToObject<Util.WebControl.ComplexFilters>(f);
_baseFiles = b;
}
} #endregion /// <summary>
/// 获取SQL条件
/// </summary>
/// <returns></returns>
public string GetSqlWhere()
{
return GetSql(_filterObj);
} /// <summary>
/// 处理SQL查询条件,含子查询
/// </summary>
/// <param name="_fObj">查询对象</param>
/// <returns></returns>
private string GetSql(Util.WebControl.ComplexFilters _fObj)
{
if (_fObj == null)
{
return "";
} bool _isFirst = true;//标识是否为首次加载有效字段条件,作为添加AND或OR关键字
StringBuilder _sqlWhere = new StringBuilder("");
//处理字段查询明细
if (_fObj.rules != null && _fObj.rules.Count > )
{
foreach (var item in _fObj.rules)
{
if (!string.IsNullOrEmpty(item.field) && !string.IsNullOrEmpty(item.op))
{
if (_isFirst != true)
{
//非首个条件添加AND或者OR
_sqlWhere.AppendFormat(" {0} ", _fObj.groupOp);
}
_sqlWhere.Append(getFieldFilter(item));
_isFirst = false;
}
}
}
//处理嵌套查询
if (_fObj.groups != null && _fObj.groups.Count > )
{
foreach (var item in _fObj.groups)
{
string _child = GetSql(item);
if (!string.IsNullOrEmpty(_child))
{
_sqlWhere.AppendFormat(" {0} {1}", _fObj.groupOp, _child);
}
}
} if (_sqlWhere.Length > )
{
return string.Format(" ({0}) ", _sqlWhere.ToString());
}
else
{
return "";
}
} /// <summary>
/// 处理单个字段查询,匹配数据类型及查询方式
/// </summary>
/// <param name="_fil">查询字段对象</param>
/// <returns></returns>
private string getFieldFilter(FilterItem _fil)
{
if (string.IsNullOrEmpty(_fil.op) || string.IsNullOrEmpty(_fil.field))
{
return "";
}
var _dataType = getDataType(_fil.field);//字段对象
string _reValue = "";
if (_dataType.MQF_DataType == "string")
{//字段为字符串时的查询
#region 字符串查询 if (_fil.op == "eq" && !string.IsNullOrEmpty(_fil.data))
{//等于
_reValue = string.Format(" {0}='{1}' ", _fil.field, _fil.data);
}
else if (_fil.op == "ne" && !string.IsNullOrEmpty(_fil.data))
{//不等于
_reValue = string.Format(" {0}<>'{1}'", _fil.field, _fil.data);
}
else if (_fil.op == "bw" && !string.IsNullOrEmpty(_fil.data))
{//开头是
_reValue = string.Format(" {0} Like '{1}%' ", _fil.field, _fil.data);
}
else if (_fil.op == "bn" && !string.IsNullOrEmpty(_fil.data))
{//开头不是
_reValue = string.Format(" {0} not Like '{1}%' ", _fil.field, _fil.data);
}
else if ((_fil.op == "in" || _fil.op == "ni") && !string.IsNullOrEmpty(_fil.data))
{//属于、不属于
//处理数据项
string[] _split = _fil.data.Replace("'", "").Split(' ');
string _strSplit = "";
foreach (var item in _split)
{
if (!string.IsNullOrEmpty(item))
{
_strSplit += "'" + item + "',";
}
}
_strSplit = _strSplit.TrimEnd(',');
if (!string.IsNullOrEmpty(_strSplit))
{
if (_fil.op == "in")
{//属于项
_reValue = string.Format(" ({0} in ({1})) ", _fil.field, _fil.data);
}
else if (_fil.op == "ni")
{//不属于项
_reValue = string.Format(" ({0} not in ({1})) ", _fil.field, _fil.data);
}
}
}
else if (_fil.op == "ew" && !string.IsNullOrEmpty(_fil.data))
{//结尾是
_reValue = string.Format(" {0} Like '%{1}' ", _fil.field, _fil.data);
}
else if (_fil.op == "en" && !string.IsNullOrEmpty(_fil.data))
{//结尾不是
_reValue = string.Format(" {0} not Like '%{1}' ", _fil.field, _fil.data);
}
else if (_fil.op == "cn" && !string.IsNullOrEmpty(_fil.data))
{//包含
_reValue = string.Format(" {0} Like '%{1}%' ", _fil.field, _fil.data);
}
else if (_fil.op == "nc" && !string.IsNullOrEmpty(_fil.data))
{//不包含
_reValue = string.Format(" {0} not Like '%{1}%' ", _fil.field, _fil.data);
}
else if (_fil.op == "nu")
{//为空
_reValue = string.Format(" ({0} is Null or {0}='')", _fil.field);
}
else if (_fil.op == "nn")
{//不为空
_reValue = string.Format(" ({0} is not Null and {0}<>'')", _fil.field);
} #endregion
}
else if (_dataType.MQF_DataType == "int" || _dataType.MQF_DataType == "float")
{//字段类型为数字
#region 数字类型查询 if (_fil.op == "eq" && !string.IsNullOrEmpty(_fil.data))
{//等于
if (!Util.ValidateUtil.IsNumberSign(_fil.data) && !Util.ValidateUtil.IsDecimalSign(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为数据,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} = {1} ", _fil.field, _fil.data);
}
else if (_fil.op == "ne" && !string.IsNullOrEmpty(_fil.data))
{//不等于
if (!Util.ValidateUtil.IsNumberSign(_fil.data) && !Util.ValidateUtil.IsDecimalSign(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为数据,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} <> {1} ", _fil.field, _fil.data);
}
else if (_fil.op == "lt" && !string.IsNullOrEmpty(_fil.data))
{//小于
if (!Util.ValidateUtil.IsNumberSign(_fil.data) && !Util.ValidateUtil.IsDecimalSign(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为数据,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} < {1} ", _fil.field, _fil.data);
}
else if (_fil.op == "le" && !string.IsNullOrEmpty(_fil.data))
{//小于等于
if (!Util.ValidateUtil.IsNumberSign(_fil.data) && !Util.ValidateUtil.IsDecimalSign(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为数据,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} <= {1} ", _fil.field, _fil.data);
}
else if (_fil.op == "gt" && !string.IsNullOrEmpty(_fil.data))
{//大于
if (!Util.ValidateUtil.IsNumberSign(_fil.data) && !Util.ValidateUtil.IsDecimalSign(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为数据,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} > {1} ", _fil.field, _fil.data);
}
else if (_fil.op == "ge" && !string.IsNullOrEmpty(_fil.data))
{//大于等于
if (!Util.ValidateUtil.IsNumberSign(_fil.data) && !Util.ValidateUtil.IsDecimalSign(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为数据,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} >= {1} ", _fil.field, _fil.data);
}
else if (_fil.op == "nu")
{//为空
_reValue = string.Format(" ({0} is Null) ", _fil.field);
}
else if (_fil.op == "nn")
{//不为空
_reValue = string.Format(" ({0} is not Null) ", _fil.field);
} #endregion
}
else if (_dataType.MQF_DataType == "datetime")
{//字段类型为时间
#region 日期类型查询 if (_fil.op == "eq" && !string.IsNullOrEmpty(_fil.data))
{//等于
if (!Util.ValidateUtil.IsDate(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为日期格式,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} = '{1}' ", _fil.field, _fil.data);
}
else if (_fil.op == "ne" && !string.IsNullOrEmpty(_fil.data))
{//不等于
if (!Util.ValidateUtil.IsDate(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为日期格式,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} <> '{1}' ", _fil.field, _fil.data);
}
else if (_fil.op == "lt" && !string.IsNullOrEmpty(_fil.data))
{//小于
if (!Util.ValidateUtil.IsDate(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为日期格式,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} < '{1}' ", _fil.field, _fil.data);
}
else if (_fil.op == "le" && !string.IsNullOrEmpty(_fil.data))
{//小于等于
if (!Util.ValidateUtil.IsDate(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为日期格式,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} <= '{1}' ", _fil.field, _fil.data);
}
else if (_fil.op == "gt" && !string.IsNullOrEmpty(_fil.data))
{//大于
if (!Util.ValidateUtil.IsDate(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为日期格式,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} > '{1}' ", _fil.field, _fil.data);
}
else if (_fil.op == "ge" && !string.IsNullOrEmpty(_fil.data))
{//大于等于
if (!Util.ValidateUtil.IsDate(_fil.data))
{
throw new Util.SysException.HfQueryPlatException("查询字符串数据类型转换失败,应为日期格式,查询名称:" + _dataType.MQF_ChineseName);
}
_reValue = string.Format(" {0} >= '{1}' ", _fil.field, _fil.data);
}
else if (_fil.op == "nu")
{//为空
_reValue = string.Format(" ({0} is Null) ", _fil.field);
}
else if (_fil.op == "nn")
{//不为空
_reValue = string.Format(" ({0} is not Null) ", _fil.field);
} #endregion
} return _reValue;
} /// <summary>
/// 获取字段数据类型
/// </summary>
/// <param name="field"></param>
/// <returns></returns>
private Service.Grid.Base_QueryFieldROC getDataType(string field)
{
var _field = this._baseFiles.First(p => p.MQF_Name == field);
if (_field != null)
{
return _field;
}
else
{
throw new HFun.Util.SysException.HfQueryPlatException("查询字段数据类型匹配失败,字段:" + field);
}
}
}
以上代码还在完善中。
系统现已将服务层改为webapi,通过csla框架作为配置对象基础,使用redis进行中间数据缓存,通过webapi作为核心服务层向asp.net mvc前端提供对象及数据。
(转载请带标记《HFun.net快速开发平台》)