在开发数据库应用的过程难免会编写大量的 SQL 语句,其中大部份是查询语句;为不同情况编写查询语句是一件很烦琐的事件。用过 hibernate 或 Nhibernate 会了解到把 SQL 查询语句对象化后使用起非常方便和快捷;也大大减少在编写查询 SQL 语句所带来的错误等问题。
前段时间在编写一个数据处理类的时候同样遇到这个问题,经过一段时间思考和设计现实现了 SQL 查询语句对象化的功能;在这里我把自己小小的成果共享一下。
在讲解前先看几个例子 ( 数据是 SQLServer 的 Northwind) 注意:例子中所涉及的除查询对象化外还包含整个数据处理类的使用,那部分还在设计和完善当中。
- 以上语句是查询订单 ID为10264的订单信息
using (HFSoft.Data.IDataSession session = HFSoft.Data.DataSessionFactory.OpenSession())
{
session.Open();
HFSoft.Data.QueryCmd query = new QueryCmd("Orders");
query.Expreesion.Add( new HFSoft.Data.EqExpression("OrderID",10264));
System.Data.DataSet myDS = session.ExecuteDataSet(query.BuilderCmd(session));
}
对象生成的SQL语句:
** SELECT * FROM Orders where 1=1 And (OrderID = @OrderID0) **
- 以上语句是查询订单 ID大于10264并且小于10600的订单信息
using (HFSoft.Data.IDataSession session = HFSoft.Data.DataSessionFactory.OpenSession())
{
session.Open();
HFSoft.Data.QueryCmd query = new QueryCmd("Orders");
query.Expreesion.Add( new HFSoft.Data.LeExpression("OrderID",10264),
new HFSoft.Data.RtExpression("OrderID",10600));
System.Data.DataSet myDS = session.ExecuteDataSet(query.BuilderCmd(session));
}
对象生成的SQL语句:
** SELECT * FROM Orders where 1=1 And (OrderID > @OrderID0) And (OrderID < @OrderID1) **
- 以上语句是查询订单 ID大于10264并且小于10600或编号是10601,10602,10605的订单信息
using (HFSoft.Data.IDataSession session = HFSoft.Data.DataSessionFactory.OpenSession())
{
session.Open();
HFSoft.Data.QueryCmd query = new QueryCmd("Orders");
query.Expreesion.Add( new HFSoft.Data.LeExpression("OrderID",10264),
new HFSoft.Data.RtExpression("OrderID",10600));
query.Expreesion.Add(HFSoft.Data.UintType.Or, new HFSoft.Data.InExpression("OrderID", new int []{10601,10602,10605}));
System.Data.DataSet myDS = session.ExecuteDataSet(query.BuilderCmd(session)); }
对象生成的 SQL语句:
** SELECT * FROM Orders where 1=1 And (OrderID > @OrderID0) And (OrderID < @OrderID1) Or (OrderID in (@OrderID20,@OrderID21,@OrderID22)) **
从上面的例子我们可以看到对不同的条件进行数据查询只是一件很简单的事情,你并不用为不同的查询情况写相应 SQL语句。
接下来讲术这个查询对象实现,对象的最终就是把不同字符串并起来生成相应的 SQL语句;SQL语句查询语句主要分为以下几大部份:获取的字段,表名称,条件,排序,分组;了解SELECT语句的对查询语句的组成部分比较了解。
其中比较难的就是条件部分处理 ,因为条件的组合是情况是比较多;所以设计起来相对比较复杂。在设计的过程中把条件单独抽取出来,并生成接口对条件的表达式进行描述:
///
1<summary>
2
3/// 表达式描述接口
4
5/// 用于SQL语句条件表达式的描述
6
7/// </summary>
public interface IExpression
{
///
1<summary>
2
3/// 获取表达式
4
5/// </summary>
///
1<param name="driver"/>
数据处理设备提供者
///
1<returns> string </returns>
string GetFilter(HFSoft.Data.IDriverType driver);
///
1<summary>
2
3/// 获取表达式相关的参数
4
5/// </summary>
///
1<param name="driver"/>
数据处理设备提供者
///
1<returns> System.Data.IDataParameter[] </returns>
System.Data.IDataParameter[] GetDataParams(HFSoft.Data.IDriverType driver);
///
1<summary>
2
3/// 序列标识
4
5/// 本属性用于内部处理
6
7/// </summary>
string Sequence
{
get ;
set ;
}
///
1<summary>
2
3/// 添加表达式
4
5/// </summary>
///
1<param name="unittype"/>
合并类型(or|and)
///
1<param name="expressions"/>
表达式对象
void Add(UintType unittype, params IExpression[] expressions );
///
1<summary>
2
3/// 添加表达式
4
5/// </summary>
///
1<param name="expressions"/>
表达式对象
void Add( params IExpression[] expressions );
}
在接口描述中有很多地方离不开 HFSoft.Data.IDriverType它是用于描述数据库类型。根据HFSoft.Data.IDriverType 对应生成SqlServer,MySql,Oracle等数据库的条件表达式。
为什么 IExpression具有Add方法,并且添加的对象也是IExpression;因为条件自己可以包含多个子表达式,只有这样才能够灵活组合成复杂的条件表达式。
接下来看下基于这个接口的实现
///
1<summary>
2
3/// 表达式基础类
4
5/// </summary>
[Serializable]
public class Expression:IExpression
{
private string mName;
///
1<summary>
2
3/// 获取或设置相关的字段名
4
5/// </summary>
public string Name
{
get
{
return mName;
}
set
{
mName = value ;
}
}
private object mValue;
///
1<summary>
2
3/// 获取或设置相关的字段值
4
5/// </summary>
public object Value
{
get
{
return mValue;
}
set
{
mValue = value ;
}
}
private string mSequence = "";
///
1<summary>
2
3/// 获取或设置相关标识
4
5/// 本属性用于内部处理
6
7/// </summary>
public string Sequence
{
get
{
return mSequence;
}
set
{
mSequence = value ;
}
}
#region IExpression 成员
///
1<summary>
2
3/// 获取表达式
4
5/// </summary>
///
1<param name="driver"/>
数据处理设备提供者
///
1<returns> string </returns>
public virtual string GetFilter(HFSoft.Data.IDriverType driver)
{
return " 1=1 " + GetSubString(driver);
}
///
1<summary>
2
3/// 获取表达式相关的参数
4
5/// </summary>
///
1<param name="driver"/>
数据处理设备提供者
///
1<returns> System.Data.IDataParameter[] </returns>
public virtual System.Data.IDataParameter[] GetDataParams(HFSoft.Data.IDriverType driver)
{
return GetSubParams(driver);
}
#endregion
private System.Collections.ArrayList _Expressions = new System.Collections.ArrayList();
private System.Collections.ArrayList _Units = new System.Collections.ArrayList();
///
1<summary>
2
3/// 添加相关表达式
4
5/// </summary>
///
1<param name="expressions"/>
表达式对象
public void Add( params IExpression[] expressions )
{
Add(UintType.And,expressions);
}
///
1<summary>
2
3/// 添加相关表达式
4
5/// </summary>
///
1<param name="unittype"/>
表达式合并类型
///
1<param name="expressions"/>
表达式对象
public void Add(UintType unittype, params IExpression[] expressions )
{
if (expressions != null )
foreach (IExpression exp in expressions)
{
if (exp != null )
{
_Units.Add(unittype.ToString());
exp.Sequence = this .Sequence +_Expressions.Count;
_Expressions.Add(exp);
}
}
}
///
1<summary>
2
3/// 获取内部表达式
4
5/// </summary>
///
1<param name="driver"/>
数据设备提供者
///
1<returns> string </returns>
protected string GetSubString(HFSoft.Data.IDriverType driver)
{
if (_Units.Count == 0)
return "";
System.Text.StringBuilder sb = new System.Text.StringBuilder();
for ( int i =0;i< this ._Units.Count;i++)
{
sb.Append(" " + this ._Units[i] +" ("+ ((IExpression)_Expressions[i]).GetFilter(driver)+")");
}
return sb.ToString();
}
///
1<summary>
2
3/// 获以内部表达式的参数值
4
5/// </summary>
///
1<param name="driver"/>
数据设备提供者
///
1<returns> System.Data.IDataParameter[] </returns>
protected System.Data.IDataParameter[] GetSubParams(HFSoft.Data.IDriverType driver)
{
if (_Expressions.Count ==0)
<