在開發數據庫應用的過程難免會編寫大量的SQL語句,其中大部份是查詢語句;為不同情況編寫查詢語句是一件很煩瑣的事件。用過hibernate或Nhibernate會了解到把SQL查詢語句對象化后使用起非常方便和快捷;也大大減少在編寫查詢SQL語句所帶來的錯誤等問題。
前段時間在編寫一個數據處理類的時候同樣遇到這個問題,經過一段時間思考和設計現實現了SQL查詢語句對象化的功能;在這里我把自己小小的成果共享一下。
在講解前先看幾個例子(數據是SQLServer的Northwind)注意:例子中所涉及的除查詢對象化外還包含整個數據處理類的使用,那部分還在設計和完善當中。
1)以上語句是查詢訂單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)
2)以上語句是查詢訂單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)
4)以上語句是查詢訂單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語句的對查詢語句的組成部分比較了解。
其中比較難的就是條件部分處理,因為條件的組合是情況是比較多;所以設計起來相對比較復雜。在設計的過程中把條件單獨抽取出來,并生成接口對條件的表達式進行描述:
/// <summary>
/// 表達式描述接口
/// 用于SQL語句條件表達式的描述
/// </summary>
public interface IExpression
{
/// <summary>
/// 獲取表達式
/// </summary>
/// <param name="driver">數據處理設備提供者</param>
/// <returns>string</returns>
string GetFilter(HFSoft.Data.IDriverType driver);
/// <summary>
/// 獲取表達式相關的參數
/// </summary>
/// <param name="driver">數據處理設備提供者</param>
/// <returns>System.Data.IDataParameter[]</returns>
System.Data.IDataParameter[] GetDataParams(HFSoft.Data.IDriverType driver);
/// <summary>
/// 序列標識
/// 本屬性用于內部處理
/// </summary>
string Sequence
{
get;
set;
}
/// <summary>
/// 添加表達式
/// </summary>
/// <param name="unittype">合并類型(or|and)</param>
/// <param name="expressions">表達式對象</param>
void Add(UintType unittype,params IExpression[] expressions );
/// <summary>
/// 添加表達式
/// </summary>
/// <param name="expressions">表達式對象</param>
void Add(params IExpression[] expressions );
}
在接口描述中有很多地方離不開HFSoft.Data.IDriverType它是用于描述數據庫類型。根據HFSoft.Data.IDriverType 對應生成SqlServer,MySQL,Oracle等數據庫的條件表達式。
為什么IExpression具有Add方法,并且添加的對象也是IExpression;因為條件自己可以包含多個子表達式,只有這樣才能夠靈活組合成復雜的條件表達式。
接下來看下基于這個接口的實現
/// <summary>
/// 表達式基礎類
/// </summary>
[Serializable]
public class Expression:IExpression
{
private string mName;
/// <summary>
/// 獲取或設置相關的字段名
/// </summary>
public string Name
{
get
{
return mName;
}
set
{
mName = value;
}
}
private object mValue;
/// <summary>
/// 獲取或設置相關的字段值
/// </summary>
public object Value
{
get
{
return mValue;
}
set
{
mValue = value;
}
}
private string mSequence = "";
/// <summary>
/// 獲取或設置相關標識
/// 本屬性用于內部處理
/// </summary>
public string Sequence
{
get
{
return mSequence;
}
set
{
mSequence = value;
}
}
#region IExpression 成員
/// <summary>
/// 獲取表達式
/// </summary>
/// <param name="driver">數據處理設備提供者</param>
/// <returns>string</returns>
public virtual string GetFilter(HFSoft.Data.IDriverType driver)
{
return " 1=1 " + GetSubString(driver);
}
/// <summary>
/// 獲取表達式相關的參數
/// </summary>
/// <param name="driver">數據處理設備提供者</param>
/// <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();
/// <summary>
/// 添加相關表達式
/// </summary>
/// <param name="expressions">表達式對象</param>
public void Add(params IExpression[] expressions )
{
Add(UintType.And,expressions);
}
/// <summary>
/// 添加相關表達式
/// </summary>
/// <param name="unittype">表達式合并類型</param>
/// <param name="expressions">表達式對象</param>
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);
}
}
}
/// <summary>
/// 獲取內部表達式
/// </summary>
/// <param name="driver">數據設備提供者</param>
/// <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();
}
/// <summary>
/// 獲以內部表達式的參數值
/// </summary>
/// <param name="driver">數據設備提供者</param>
/// <returns>System.Data.IDataParameter[]</returns>
protected System.Data.IDataParameter[] GetSubParams(HFSoft.Data.IDriverType driver)
{
if(_Expressions.Count ==0)
return null;
if(_Expressions.Count ==1)
{
return ((IExpression)_Expressions[0]).GetDataParams(driver);
}
System.Collections.ArrayList lst = new System.Collections.ArrayList();
foreach(IExpression exp in this._Expressions)
{
System.Data.IDataParameter[] ps = exp.GetDataParams(driver);
if(ps !=null && ps.Length >0)
{
foreach(System.Data.IDataParameter dp in ps)
{
lst.Add(dp);
}
}
}
Array array = Array.CreateInstance(typeof(System.Data.IDataParameter),lst.Count);
lst.CopyTo(array);
return array as System.Data.IDataParameter[];
}
}
其實Expression只是一個模板類,它自己本生并沒有條件處理的能力只是一個簡單的1=1;下面我們根據這個模板類派生出具體表達式類型。
/// <summary>
/// 基礎表達式抽象類
/// </summary>
[Serializable]
public abstract class BaseExpression:Expression
{
/// <summary>
/// 獲取表達式參數對象集
/// </summary>
/// <param name="driver">數據設備提供者</param>
/// <returns>System.Data.IDataParameter[]</returns>
public override System.Data.IDataParameter[] GetDataParams(HFSoft.Data.IDriverType driver)
{
System.Data.IDataParameter p1 = driver.GetParameter(Name+ Sequence,Value);
return ParamsConcat(new System.Data.IDataParameter[]{p1},GetSubParams(driver));
}
/// <summary>
/// 獲取表達式
/// </summary>
/// <param name="driver">數據設備提供者</param>
/// <returns>string</returns>
public override string GetFilter(HFSoft.Data.IDriverType driver)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append(Name);
sb.Append(GetCompareType());
sb.Append(driver.FormatNameForParameter(Name + this.Sequence));
return sb.ToString();
}
/// <summary>
/// 表達式類型
/// =,like等
/// </summary>
/// <returns>string</returns>
protected abstract string GetCompareType();
}
/// <summary>
/// 等于表達式
/// </summary>
[Serializable]
public class EqExpression:BaseExpression
{
/// <summary>
/// 構造等于表達式對象
/// </summary>
public EqExpression()
{
}
/// <summary>
/// 構造指定名稱和值的等于表達式對象
/// </summary>
/// <param name="name">名稱</param>
/// <param name="value">值</param>
public EqExpression(string name,object value)
{
Name = name;
Value = value;
}
/// <summary>
/// 表達式比較符
/// </summary>
/// <returns>string</returns>
protected override string GetCompareType()
{
return " = ";
}
}
整個條件對象的設計就完成了,文章代碼中只有實現了等于的表達式對象;我們可以按自己情況編寫更復雜的表達式。條件表達式對象在整個查詢對象中是比較核心的部心,因為在整個SQL查詢語句中除了這些條件外其它地方都是固定的,剩下的就是把些不同的字符串合并起來,這些東西就不詳細說了大家比較了解。
其實Expression只是一個模板類,它自己本生并沒有條件處理的能力只是一個簡單的1=1;下面我們根據這個模板類派生出具體表達式類型。
/// <summary>
/// 基礎表達式抽象類
/// </summary>
[Serializable]
public abstract class BaseExpression:Expression
{
/// <summary>
/// 獲取表達式參數對象集
/// </summary>
/// <param name="driver">數據設備提供者</param>
/// <returns>System.Data.IDataParameter[]</returns>
public override System.Data.IDataParameter[] GetDataParams(HFSoft.Data.IDriverType driver)
{
System.Data.IDataParameter p1 = driver.GetParameter(Name+ Sequence,Value);
return ParamsConcat(new System.Data.IDataParameter[]{p1},GetSubParams(driver));
}
/// <summary>
/// 獲取表達式
/// </summary>
/// <param name="driver">數據設備提供者</param>
/// <returns>string</returns>
public override string GetFilter(HFSoft.Data.IDriverType driver)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
sb.Append(Name);
sb.Append(GetCompareType());
sb.Append(driver.FormatNameForParameter(Name + this.Sequence));
return sb.ToString();
}
/// <summary>
/// 表達式類型
/// =,like等
/// </summary>
/// <returns>string</returns>
protected abstract string GetCompareType();
}
/// <summary>
/// 等于表達式
/// </summary>
[Serializable]
public class EqExpression:BaseExpression
{
/// <summary>
/// 構造等于表達式對象
/// </summary>
public EqExpression()
{
}
/// <summary>
/// 構造指定名稱和值的等于表達式對象
/// </summary>
/// <param name="name">名稱</param>
/// <param name="value">值</param>
public EqExpression(string name,object value)
{
Name = name;
Value = value;
}
/// <summary>
/// 表達式比較符
/// </summary>
/// <returns>string</returns>
protected override string GetCompareType()
{
return " = ";
}
}
整個條件對象的設計就完成了,文章代碼中只有實現了等于的表達式對象;我們可以按自己情況編寫更復雜的表達式。條件表達式對象在整個查詢對象中是比較核心的部心,因為在整個SQL查詢語句中除了這些條件外其它地方都是固定的,剩下的就是把些不同的字符串合并起來,這些東西就不詳細說了大家比較了解。
http://www.49028c.com/niit007/archive/2006/08/13/475581.html
新聞熱點
疑難解答