欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

告別ADO.NET實(shí)現(xiàn)應(yīng)用系統(tǒng)無縫切換的煩惱(總結(jié)篇)

 更新時(shí)間:2009年11月02日 14:21:43   作者:  
說起ADO.NET,就扯上了數(shù)據(jù)庫訪問類庫了,現(xiàn)在的每個(gè)項(xiàng)目的數(shù)據(jù)庫訪問類應(yīng)該說都很強(qiáng)的了,經(jīng)常就聽到說我的我們的數(shù)據(jù)庫訪問類怎么怎么強(qiáng)大而且支持多數(shù)據(jù)庫,現(xiàn)在的大家做的項(xiàng)目里用的數(shù)據(jù)庫訪問類庫我想也都是支持多數(shù)據(jù)庫吧,支持到什么程度我就不知道了
可能只是那么想也是那么設(shè)計(jì)的,要支持多數(shù)據(jù)庫,要能支持多數(shù)據(jù)庫,萬一要是以后數(shù)據(jù)庫變了怎么辦?萬一要是。。。怎么辦?這些顧慮很多時(shí)候是不必要的,反而繞了彎子。大都是做項(xiàng)目應(yīng)用系統(tǒng)而非產(chǎn)品,即使要用不同的數(shù)據(jù)庫了,基本上是吧上一個(gè)項(xiàng)目全COPY過來,修修改改OK了。產(chǎn)品可能就不一樣了,那才可能要支持真正的多數(shù)據(jù)庫,才可能會(huì)面對(duì)真正的數(shù)據(jù)庫訪問類庫的多數(shù)據(jù)庫的實(shí)際檢驗(yàn)。ADO.NET2.0下增強(qiáng)了數(shù)據(jù)庫訪問的功能,也就是工廠式類庫,提到工廠式數(shù)據(jù)庫訪問,網(wǎng)上可就多了,ADO.NET2.0增強(qiáng)的工廠式網(wǎng)上也很多了,都說只要改動(dòng)webconfig里的數(shù)據(jù)庫連接就行了,其它什么地方都不用改了,看了幾篇都是點(diǎn)了下,不知道做過充分測(cè)試沒有,應(yīng)該說在實(shí)際的多數(shù)據(jù)庫產(chǎn)品系統(tǒng)中,還要做很多修正,完善和測(cè)試的。
說正題,假設(shè)(只是假設(shè),真的不會(huì)這么變態(tài),呵呵)一產(chǎn)品系統(tǒng)要支持ACCESS,SYBASE,SQL SERVER,ORACEL數(shù)據(jù)庫,系統(tǒng)開發(fā)完后,要求只改動(dòng)數(shù)據(jù)庫的連接,也就是說只改動(dòng)webconfig,來實(shí)現(xiàn)系統(tǒng)的無縫切換,其它什么也不改動(dòng),可能有的覺得簡單,但是要經(jīng)得起實(shí)際檢驗(yàn)還是要花點(diǎn)時(shí)間測(cè)試的,當(dāng)然寫是不算難,見到過有的應(yīng)用系統(tǒng)開發(fā)中,所有的DML語句都以XML形式放在config配置文件里,然后用封裝好的數(shù)據(jù)庫訪問組件讀config配置文件執(zhí)行SQL語句,開發(fā)人員只要建個(gè)config文件把增刪改查語句寫那里就可以,當(dāng)然這么來有個(gè)好處,就是做到了與數(shù)據(jù)庫的無關(guān)性了,如果數(shù)據(jù)庫訪問組件做的完善的,當(dāng)然是可以做到系統(tǒng)無縫切換到其它數(shù)據(jù)庫的,當(dāng)然同時(shí)也有缺陷,項(xiàng)目中不僅僅是DML語句吧,有的稍微復(fù)雜點(diǎn)的邏輯,存儲(chǔ)過程要用下吧,我自己也趨向于喜歡用存儲(chǔ)過程,自定義函數(shù)來處理稍微復(fù)雜的邏輯,而且把DML語句都放在配置文件里我也是不能忍受的,可能是一個(gè)個(gè)人的習(xí)慣吧。
繼續(xù),下面開始我要說的利用ADO.NET2.0及以上版本新增的工廠式數(shù)據(jù)庫訪問實(shí)現(xiàn)應(yīng)該系統(tǒng)的無縫切換,要實(shí)現(xiàn)無縫切換,當(dāng)然還是要有前提條件了,就是各個(gè)不同的數(shù)據(jù)庫之間的表和其它對(duì)象都已經(jīng)成功移植了,沒有這個(gè)前提,純用ADO.NET做系統(tǒng)無縫切換那是不可能的了,比如SQL SERVER中寫的存儲(chǔ)過程,自定義函數(shù)直接復(fù)制到ORACLE上就行了嗎?當(dāng)然是不行,寫法及變量定義要做些調(diào)整才可以成功移植的,還有變結(jié)構(gòu)字段類型等等的都可能是要做相應(yīng)調(diào)整,這些都做好了才能談系統(tǒng)的無縫切換。要做的無縫切換,數(shù)據(jù)庫訪問層的代碼中最好(并非絕對(duì))不應(yīng)該出現(xiàn)SqlCommand,SqlDataAdapter,SqlClient,SqlXXX吧,要切換到ORACLE數(shù)據(jù)上,甲骨文會(huì)把你的SqlXXX玩死的,ORACLE里可以O(shè)racleCommand,OracleXXX,還有程序執(zhí)行帶參數(shù)語句時(shí),比如 where userid=@userid,甲骨文也會(huì)玩死你的,oracle里可是where userid=:userid,@前綴在ACCESS,SYBASE,SQL SERVER里是都認(rèn)得,還有還有字段名的寫法問題,ORACLE里可以區(qū)分大小寫的,比如可能大多習(xí)慣這樣命名屬性和自段,UserName,UserAge,如果在ORACLE里這么命名的話,系統(tǒng)開發(fā)過程中的那種痛苦也許只有經(jīng)歷過的人才知道,ORACLE堅(jiān)持大寫為標(biāo)準(zhǔn),記得很久很久以前的一個(gè)夏天的晚上,那時(shí)我還是年輕的80后,一位數(shù)據(jù)庫設(shè)計(jì)比較N的人提到過,盡量在數(shù)據(jù)庫設(shè)計(jì)和T-SQL編程中采用大寫標(biāo)準(zhǔn),基本上接觸的SQL SERVER數(shù)據(jù)庫較多,也習(xí)慣了表名,字段名的大寫設(shè)計(jì),后來發(fā)現(xiàn)確實(shí)是有道理的。這里提到的問題都是在下面的各個(gè)方法中為了兼容不同的數(shù)據(jù)庫需要面對(duì)的問題,具體講到每個(gè)執(zhí)行方法時(shí)再具體解釋。剛才說SqlCommand,OracleComand都是各自認(rèn)得,但是DbCommand可是大家都認(rèn)得的,暫且叫抽象對(duì)象吧,還有DbConnection,DbDataAdapter等都是他們都認(rèn)得的,所以在做支持多數(shù)據(jù)庫訪問類庫時(shí),就可以用這些對(duì)象了,根據(jù)這些對(duì)象再創(chuàng)建具體對(duì)象。ADO.NET2.0中數(shù)據(jù)庫訪問工廠中有個(gè) DbProviderFactory 對(duì)象,也就是通常說的DataProvider了,正是這個(gè)起了關(guān)鍵和方便的作用,是用來創(chuàng)建提供程序?qū)?shù)據(jù)源類的實(shí)現(xiàn)的實(shí)例(就是用來創(chuàng)建實(shí)例)。另外數(shù)據(jù)庫操作還要用到參數(shù)吧,DbParameter,DbParameterCollection下面都需要用到,先貼一段類庫的構(gòu)造函數(shù),因?yàn)楣灿脤?duì)象需要先實(shí)例化。
復(fù)制代碼 代碼如下:

public DbConnection conn;//抽象類型
private DbCommand cmd;//抽象類型
private DbProviderFactory provider;
private DbParameter Para;//不同數(shù)據(jù)庫參數(shù)類型的抽象類型
private DbDataAdapter Adapter;//對(duì)應(yīng)不同數(shù)據(jù)庫的數(shù)據(jù)適配器
Dictionary<Type, String> ParametersFormat;//不同數(shù)據(jù)庫參數(shù)格式化類型
public string retParaformat = string.Empty;//最終返回的格式化標(biāo)志,如@{0},:{0}
public DataProviderFactory()
{
//從配置文件中取出標(biāo)示數(shù)據(jù)庫類型的字符串并通過ProviderName的不同支持不同類型的數(shù)據(jù)庫
string providerName = ConfigurationManager.ConnectionStrings["ConnStr"].ProviderName;//也可以用索引,從1開始
//創(chuàng)建一個(gè)數(shù)據(jù)庫對(duì)應(yīng)的實(shí)例,使用該實(shí)例就可以創(chuàng)建對(duì)應(yīng)的connection,command 和adapater等等對(duì)象
provider = DbProviderFactories.GetFactory(providerName);
//創(chuàng)建具體的數(shù)據(jù)庫連接類型和命令執(zhí)行類型
conn = provider.CreateConnection();
conn.ConnectionString = ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString;
cmd = provider.CreateCommand();
cmd.Connection = conn;
//創(chuàng)建具體的參數(shù)類型
Para = provider.CreateParameter();
//創(chuàng)建具體的適配器類型
Adapter = provider.CreateDataAdapter();
//不同數(shù)據(jù)庫參數(shù)前綴格式化
ParametersFormat = new Dictionary<Type, String>();
ParametersFormat.Add(typeof(System.Data.SqlClient.SqlCommand), "@{0}");//因SQL SERVER只返回{0}沒有@前綴,在此初始化處理
//返回格式化標(biāo)志
retParaformat = GetParameterFormat(cmd);
}

上面那段代碼中,可以看到我定義了兩個(gè)公共變量,其中conn在外部只會(huì)有一個(gè)地方調(diào)用它,那就就是執(zhí)行DataReader方法的時(shí)候了,因?yàn)榇蠹叶贾纃r在離開方法體時(shí),連接是不能關(guān)閉的,
所以只能在外部調(diào)用處顯示關(guān)閉連接對(duì)象 ,必須定義為公共類型了,還有一個(gè)公共參數(shù)變量是格式化字符串的字符型。前面說到Oracle參數(shù)前綴是冒號(hào):,其它幾個(gè)數(shù)據(jù)庫前綴是@符號(hào),怎么樣在切換數(shù)據(jù)庫以后程序能動(dòng)態(tài)識(shí)別參數(shù)前綴并組合相應(yīng)的參數(shù)變量呢?如果手動(dòng)寫代碼用數(shù)據(jù)庫對(duì)象類型枚舉去一個(gè)個(gè)判斷,那這數(shù)據(jù)庫工廠也沒什么意義了,最終找到了一個(gè)相當(dāng)完美的解決方式(微軟就是微軟,都能替你想到,別人想不強(qiáng)大都難啦,呵呵),其實(shí)在做測(cè)試的時(shí)侯到各不同數(shù)據(jù)庫的參數(shù)前綴這就有點(diǎn)犯難了,手寫代碼一個(gè)個(gè)處理吧,沒問題,覺得應(yīng)該有簡單的方法吧,MS從來就不是傻瓜呀,正好前兩天在園子首頁就有篇提到這個(gè)問題,而且給出相關(guān)提示,根據(jù)給的提示再gg了一把,終于找到了一個(gè)便捷的辦法。還是貼方法代碼好了,如下:
復(fù)制代碼 代碼如下:

/// <summary>
/// 根據(jù)不同的數(shù)據(jù)庫命令對(duì)象返回該類型數(shù)據(jù)庫參數(shù)的前綴格式化字符串
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
private string GetParameterFormat(DbCommand command)
{
if (!ParametersFormat.ContainsKey(command.GetType()))
{
this.Open();//讀取參數(shù)前綴時(shí)需打開數(shù)據(jù)庫連接
ParametersFormat.Add(
command.GetType(),
command.Connection.GetSchema("DataSourceInformation")
.Rows[0]["ParameterMarkerFormat"].ToString());
//conn.Close();在真正執(zhí)行語句的時(shí)候去關(guān)閉,避免重復(fù)打開
}
return ParametersFormat[command.GetType()];
}

就是這個(gè)了 ParameterMarkerFormat,即參數(shù)標(biāo)志符格式化,如連接oracle數(shù)據(jù)庫則返回:{0},其它幾個(gè)數(shù)據(jù)庫返回@{0},惟獨(dú)SQL SERVER數(shù)據(jù)庫返回{0},到底是MS自己的東西,就是要返回跟別人不一樣的東西,也就因?yàn)檫@個(gè),這個(gè)類庫里很遺憾不得不出現(xiàn)一個(gè)SqlCommand,就是上面貼出的構(gòu)造函數(shù)里的初始化那ParametersFormat.Add(typeof(System.Data.SqlClient.SqlCommand), "@{0}");必須這樣做下處理,另外包括GetParameterFormat方法里的判斷,即不是SQL SERVER數(shù)據(jù)庫時(shí)才去讀參數(shù)前綴,如果是就直接返回@{0},有了這個(gè)格式化的前綴字符串,就好辦了.那參數(shù)名稱的賦值就可以類似這樣了string.Format("@{0}", ParaName);
下面說說各通用的方法和調(diào)用,之前的sqlhelper.cs,oraclehelper.cs,xxhelper.cs中的執(zhí)行方法大多都很多,有帶參數(shù)執(zhí)行的語句的方法,不帶參數(shù)執(zhí)行的語句的方法,帶參數(shù)執(zhí)行的方法體里面還要循環(huán)參數(shù),這些都我都精簡掉了,最終演變成了peacehelper.cs(開個(gè)玩笑).帶參執(zhí)行和不帶參執(zhí)行DML語句,其實(shí)是可以合并成一個(gè)方法,各個(gè)參數(shù)都是保存在數(shù)據(jù)庫命令對(duì)象的參數(shù)集合中的,我們可以把創(chuàng)建好的命令對(duì)象返回給外部程序調(diào)用處,調(diào)用的地方要帶參執(zhí)行語句的話,就定義參數(shù)并賦值就行了,不帶參執(zhí)行的話就不用定義參數(shù)了,這么以來就只需要寫一個(gè)方法就行了,而且執(zhí)行帶摻的語句時(shí)不用再循環(huán)參數(shù)集合了,因?yàn)樵谡{(diào)用處定義參數(shù)時(shí),該參數(shù)已經(jīng)綁定都了DbCommand對(duì)象了.寫一個(gè)返回給外部調(diào)用的數(shù)據(jù)庫命令對(duì)象的方法,如下:
復(fù)制代碼 代碼如下:

/// <summary>
/// 抽象參數(shù)集合類型
/// </summary>
/// <returns></returns>
public DbParameterCollection GetParmCollection()
{
return cmd.Parameters;
}

添加參數(shù)的方法如下:
復(fù)制代碼 代碼如下:

/// <summary>
/// 添加參數(shù)
/// </summary>
/// <param name="ParaName">參數(shù)名稱</param>
/// <param name="SqlType">參數(shù)數(shù)據(jù)類型</param>
/// <param name="ParaValue">參數(shù)值</param>
/// <param name="ParaCollect">參數(shù)對(duì)象的集合</param>
public void AddParam(string ParaName, DbType SqlType, object ParaValue, DbParameterCollection ParaCollect)
{
//不允許將一個(gè)DbCommand對(duì)象的Parameters插入到另外一個(gè)DbCommand對(duì)象,那么多個(gè)參數(shù)的話可以加上下面一句判斷
//如果已經(jīng)存在至少一個(gè)對(duì)象時(shí),再深層拷貝一個(gè)
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat, ParaName);
Para.DbType = SqlType;
if (ParaValue == null)
{
Para.Value = string.Empty;//DBNull.Value;
}
else
{
Para.Value = ParaValue;
}
ParaCollect.Add(Para);
}

上面有句判斷,如果有多個(gè)參數(shù)會(huì)出異常,網(wǎng)上搜了下,注釋就是網(wǎng)上的解釋,不多說了,意思很清楚。這個(gè)方法里還有一點(diǎn),如果DbType參數(shù)不要的話測(cè)試也是可以通過的,猜想如果不顯示指定參數(shù)數(shù)據(jù)類型的話,是不是都默認(rèn)為object類型?這樣的話會(huì)不會(huì)涉及一個(gè)裝拆箱的操作呢?但是開發(fā)人員在調(diào)用處添加參數(shù),是不應(yīng)該關(guān)心參數(shù)的數(shù)據(jù)類型才對(duì),干脆數(shù)據(jù)類型參數(shù)不要了,改成如下方法了:
復(fù)制代碼 代碼如下:

public void AddParam(string ParaName, object ParaValue, DbParameterCollection ParaCollect)
{
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat, ParaName);//將參數(shù)格式化為具體的數(shù)據(jù)庫參數(shù)格式
if (ParaValue == null)
{
Para.Value = string.Empty;
}
else
{
Para.Value = ParaValue;
}
ParaCollect.Add(Para);
}

為了兼容不同的數(shù)據(jù)庫(主要是oracle變量特殊問題),添加參數(shù)的方法分兩種,一種是普通帶參執(zhí)行的DML語句,一種是代參執(zhí)行的存儲(chǔ)過程。對(duì)于SQL SERVER數(shù)據(jù)庫即使是存儲(chǔ)過程
變量參數(shù)仍是@前綴,ORACLE存儲(chǔ)過程又是什么前綴呢?很遺憾,ORACLE存儲(chǔ)過程的參數(shù)變量是不需要任何前綴的,為了單獨(dú)兼容這一點(diǎn),對(duì)于不同數(shù)據(jù)庫如果調(diào)用的存儲(chǔ)過程有參數(shù)
的話,建議用下面的三個(gè)添加參數(shù)的方法:
復(fù)制代碼 代碼如下:

/// <summary>
/// 存儲(chǔ)過程輸入?yún)?shù)
/// </summary>
/// <param name="ParaName"></param>
/// <param name="ParaValue"></param>
/// <param name="ParaCollect"></param>
public void AddInputParam(string ParaName, object ParaValue, DbParameterCollection ParaCollect)
{
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat.Replace(":",""), ParaName);//ORACLE存儲(chǔ)過程參數(shù)前沒有冒號(hào)
if (ParaValue == null)
{
Para.Value = string.Empty;
}
else
{
Para.Value = ParaValue;
}
ParaCollect.Add(Para);
}
/// <summary>
/// 存儲(chǔ)過程輸出參數(shù)
/// </summary>
/// <param name="ParaName"></param>
/// <param name="ParaValue"></param>
/// <param name="ParaCollect"></param>
public void AddOutputParam(string ParaName, DbParameterCollection ParaCollect)
{
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat.Replace(":", ""), ParaName);
Para.Value = string.Empty;
ParaCollect.Add(Para);
ParaCollect[Para.ParameterName].Direction = System.Data.ParameterDirection.Output;//指定該參數(shù)為輸出參數(shù)
}
/// <summary>
/// 存儲(chǔ)過程返回值參數(shù)
/// </summary>
/// <param name="ParaName"></param>
/// <param name="ParaValue"></param>
/// <param name="ParaCollect"></param>
public void AddReturnParam(string ParaName,DbParameterCollection ParaCollect)
{
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat.Replace(":", ""), ParaName);
Para.Value = string.Empty;
ParaCollect.Add(Para);
ParaCollect[Para.ParameterName].Direction = System.Data.ParameterDirection.ReturnValue;//指定該參數(shù)為返回值參數(shù)
}

OK,現(xiàn)在開始說下peacehelper.cs里的八大方法(其實(shí)算起來應(yīng)該是10個(gè)),應(yīng)該來說涵蓋絕大多應(yīng)該系統(tǒng)操作數(shù)據(jù)庫的絕大部分功能,如果有特殊的操作可以在此基礎(chǔ)上添加。
第一個(gè),大家都熟悉的返回結(jié)果集:
復(fù)制代碼 代碼如下:

/// <summary>
/// 執(zhí)行SQL并返回?cái)?shù)據(jù)集
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public DataSet ExecDataSet(string Sql)
{
DataSet ds = new DataSet();
try
{
this.Open();
cmd.CommandText = Replace(Sql);
Adapter.SelectCommand = cmd;
Adapter.Fill(ds);
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}
return ds;
}

上面的方法大家看了是不是覺得既簡單又熟悉,確實(shí)是的,但仍然相當(dāng)以前的xxhelper.cs里是做了簡化的,該方法既可以直接執(zhí)行不帶參DML語句,也可以執(zhí)行帶參的,但是該方法的形參卻
只有一個(gè),之前的xxhelper.cs里帶參執(zhí)行的話,形參中大多至少還另外一個(gè)形參的,比如SqlPeremeters[]類型或參數(shù)集合類型的形參,而且方法體里面大多會(huì)循環(huán)讀取參數(shù),上面的方法里
卻沒有,都簡化掉了,唯一多了一點(diǎn)的是,所執(zhí)行的命令語句執(zhí)行前要做一個(gè)特殊字符替換,cmd.CommandText = Replace(Sql),Replace方法主要是替換參數(shù)前綴,Replace方法如下:
復(fù)制代碼 代碼如下:

/// <summary>
/// 替換DML語句里的參數(shù)前綴
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string Replace(string str)
{
return str.Replace("$", retParaformat.Substring(0, 1));
}

因?yàn)椴煌瑪?shù)據(jù)庫除了在添加參數(shù)時(shí)有前綴的區(qū)別,再具體執(zhí)行語句時(shí)也有前綴區(qū)別嘛,比如SQL SERVER里 SELECT USER_NAME,USER_AGE FROM USERS WHERE USER_ID=@USER_ID,ORACLE里是這樣的SELECT USER_NAME,USER_AGE FROM USERS WHERE USER_ID=:USER_ID,在此就需要統(tǒng)一一個(gè)前綴規(guī)則了,統(tǒng)一這樣SELECT USER_NAME,USER_AGE FROM USERS WHERE USER_ID=$USER_ID,在執(zhí)行前根據(jù)不同數(shù)據(jù)庫替換前綴$符號(hào),當(dāng)然這個(gè)約定規(guī)則不一定是最完美的,也許還存在一定的問題,寫到這我也突然想起來之前我見過別人
的系統(tǒng)中有的就是變量參數(shù)用的這種類似特殊符號(hào),肯定也是為了兼容多數(shù)據(jù)庫所作的處理了,呵呵,具體的調(diào)用及測(cè)試之后統(tǒng)一說明。還有幾個(gè)方法也和上面類似,大家都熟悉的。如下(不再做具體解釋了):
復(fù)制代碼 代碼如下:

/// <summary>
/// 執(zhí)行SQL語句并返回DataReader對(duì)象
/// </summary>
/// <param name="dbcon"></param>
/// <param name="cmdText"></param>
/// <returns></returns>
public DbDataReader ExecuteDataReader(DbConnection dbcon,string cmdText)
{
try
{
if (dbcon.State == ConnectionState.Closed)
{
dbcon.Open();
}
cmd.CommandText = Replace(cmdText);
DbDataReader dr = cmd.ExecuteReader();
cmd.Parameters.Clear();
cmd.Dispose();
return dr;
}
catch
{
dbcon.Close();//發(fā)生異常在此處關(guān)閉,否則在調(diào)用顯式處關(guān)閉
return null;
}
}

/// <summary>
/// 判斷記錄是否存在
/// </summary>
/// <param name="Sql"></param>
/// <returns></returns>
public bool Exist(string Sql)
{
bool exist;
this.Open();
cmd.CommandText = Replace(Sql);
DbDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
{
exist = true; //記錄存在
}
else
{
exist = false; //記錄不存在
}
dr.Close();
this.Close();
return exist;
}
/// <summary>
/// 執(zhí)行SQL語句
/// </summary>
/// <param name="sql"></param>
public void ExecSql(string Sql)
{
try
{
this.Open();
cmd.CommandText = Replace(Sql);
cmd.ExecuteNonQuery();
cmd.Dispose();
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}

}
/// <summary>
/// 執(zhí)行SQL語句,返回一個(gè)單值
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public string ReturnValue(string Sql)
{
object returnValue = string.Empty;
try
{
this.Open();
cmd.CommandText = Replace(Sql);
returnValue = cmd.ExecuteScalar();
if (returnValue == null)
{
returnValue = string.Empty;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}
return returnValue.ToString();
}
/// <summary>
/// 執(zhí)行多條SQL語句并啟用數(shù)據(jù)庫事務(wù)
/// </summary>
/// <param name="SQLStringList"></param>
public bool ExecSqlTran(List<String> SQLStringList)
{
this.Open();
DbTransaction trans = conn.BeginTransaction();
cmd.Transaction = trans;
try
{
for (int n = 0; n < SQLStringList.Count; n++)
{
cmd.CommandText = Replace(SQLStringList[n]);
cmd.ExecuteNonQuery();
}
trans.Commit();
return true;
}
catch
{
trans.Rollback();
return false;
}
finally
{
this.Close();
}
}

下面說下兩個(gè)存儲(chǔ)過程,存儲(chǔ)過程基本上分兩種,返回結(jié)果集的存儲(chǔ)過程和執(zhí)行業(yè)務(wù)邏輯不返回結(jié)果集但卻有返回值(如標(biāo)志等),對(duì)于需要有返回值的存儲(chǔ)過程,我個(gè)人趨向于用輸出
參數(shù)代替返回值,因?yàn)槎寄苓_(dá)到一樣的效果目的,而且輸出參數(shù)可以有多個(gè),也就可以根據(jù)需要能有多個(gè)所謂的“返回值”,所以我之前的開發(fā)中一直是用output參數(shù)來代替return參數(shù)。

復(fù)制代碼 代碼如下:

/// <summary>
/// 執(zhí)行存儲(chǔ)過程并返回結(jié)果集
/// </summary>
/// <param name="storedProcName">存儲(chǔ)過程名</param>
/// <returns>DataSet</returns>
public DataSet RunProcedure(string storedProcName)
{
DataSet ds = new DataSet();
try
{
this.Open();
cmd.CommandText = storedProcName;
cmd.CommandType = CommandType.StoredProcedure;
Adapter.SelectCommand = cmd;
//Adapter.SelectCommand.CommandTimeout = 1200;//可以設(shè)置適當(dāng)?shù)某瑫r(shí)時(shí)間(秒),避免選擇時(shí)間段過大導(dǎo)致填充數(shù)據(jù)集超時(shí)
Adapter.Fill(ds);
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}
return ds;
}
/// <summary>
/// 執(zhí)行存儲(chǔ)過程,方法不返回結(jié)果集
/// </summary>
/// <param name="storedProcName"></param>
public void RunVoidProcedure(string storedProcName)
{
cmd.CommandText = storedProcName;
cmd.CommandType = CommandType.StoredProcedure;
try
{
this.Open();
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}
}

下面說兩個(gè)反射方法,測(cè)試之后為了方便調(diào)用,減少操作添加的,一個(gè)是把實(shí)體類的屬性轉(zhuǎn)換為參數(shù),另一個(gè)是把從數(shù)據(jù)庫取出的某條記錄轉(zhuǎn)換為實(shí)體類,這兩個(gè)還是非常有用,尤其是在系統(tǒng)開發(fā)時(shí)調(diào)用比較方便,以前我是見到反射就繞道走的,這次算是第一次用反射,發(fā)現(xiàn)確實(shí)是很方便。如下:
復(fù)制代碼 代碼如下:

/// <summary>
/// 將實(shí)體類的屬性進(jìn)行參數(shù)轉(zhuǎn)換(ORACLE測(cè)試通不過,必須要求所有參數(shù)都包含在語句中才行)
/// </summary>
/// <param name="model"></param>
/// <param name="ParaCollect"></param>
//public void ConvertToParameters(object model, DbParameterCollection ParaCollect)
//{
// Type T = model.GetType();
// PropertyInfo[] propert = T.GetProperties();
// for (int i = 0; i < propert.Length; i++)
// {
// AddParam(propert[i].Name, propert[i].GetValue(model, null), ParaCollect);
// }
//}
/// <summary>
/// 將實(shí)體類的屬性進(jìn)行參數(shù)轉(zhuǎn)換
/// </summary>
/// <param name="model"></param>
/// <param name="ParaCollect"></param>
public void ConvertToParameters(object model, DbParameterCollection ParaCollect,List<string> fields)
{
Type T = model.GetType();
PropertyInfo[] propert = T.GetProperties();
for (int i = 0; i < propert.Length; i++)
{
if (fields.Contains(propert[i].Name)) //檢測(cè)必須參數(shù)化的實(shí)體屬性
{
AddParam(propert[i].Name, propert[i].GetValue(model, null), ParaCollect);
}
}
}

/// <summary>
/// 通過反射將取出的數(shù)據(jù)寫入實(shí)體類(ORACLE測(cè)試通不過,需進(jìn)行類型強(qiáng)制轉(zhuǎn)換)
/// </summary>
/// <param name="model"></param>
/// <param name="cmdText"></param>
//public void GetModel(object model, string cmdText)
//{
// PropertyInfo propertyInfo;
// DbDataReader dr = ExecuteDataReader(conn, cmdText);
// while (dr.Read())
// {
// for (int i = 0; i < dr.FieldCount; i++)
// {
// propertyInfo = model.GetType().GetProperty(dr.GetName(i));
// if (propertyInfo != null)
// {
// if (dr.GetValue(i) != DBNull.Value)
// {
// //Type t = dr.GetValue(i).GetType();
// propertyInfo.SetValue(model, dr.GetValue(i), null);
// }
// }
// }
// }
// dr.Close();
// conn.Close();
//}
/// <summary>
/// 通過反射將數(shù)據(jù)綁定到實(shí)體對(duì)象,由于不同數(shù)據(jù)庫對(duì)應(yīng)于.NET的數(shù)據(jù)類型不一樣
/// 需做強(qiáng)制類型轉(zhuǎn)換
/// </summary>
/// <param name="model"></param>
/// <param name="cmdText"></param>
public void GetModel(object model, string cmdText)
{
PropertyInfo propertyInfo;
DbDataReader dr = ExecuteDataReader(conn, cmdText);
object _value;
while (dr.Read())
{
for (int i = 0; i < dr.FieldCount; i++)
{
propertyInfo = model.GetType().GetProperty(dr.GetName(i));
if (propertyInfo != null && dr.GetValue(i) != DBNull.Value)
{
switch (propertyInfo.PropertyType.ToString())
{
case "System.String":
{
_value = Convert.ToString(dr.GetValue(i));//字符串是全球通用類型,也可以不用轉(zhuǎn)換
propertyInfo.SetValue(model, _value, null);
}break;
case "System.Int32":
{
_value = Convert.ToInt32(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
case "System.Single":
{
_value = Convert.ToSingle(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
case "System.Decimal":
{
_value = Convert.ToDecimal(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
case "System.Double":
{
_value = Convert.ToDouble(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
case "":
{
_value = Convert.ToDateTime(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
default: break;
}
}
}
}
dr.Close();
conn.Close();
}

從上面的注釋掉的方法對(duì)比中可以看到為了兼容不同的數(shù)據(jù)庫,必須要做額外的處理,比如類型轉(zhuǎn)換,SQL SERVER的int 對(duì)應(yīng)ORALCE的number,UserInfo的字段屬性UserAge定義的是int類型,連接ORALCE時(shí),.NET識(shí)別number類型為System.Decimal,把Decimal賦值給Int32當(dāng)然是不行的,所以得做強(qiáng)制轉(zhuǎn)換才行。還有一點(diǎn)要注意下,就是將數(shù)據(jù)綁定到實(shí)體對(duì)象時(shí),由于ORACLE堅(jiān)持大寫標(biāo)準(zhǔn)和解析機(jī)制,如果屬性名和字段名大小寫不一致的話,propertyInfo = model.GetType().GetProperty(dr.GetName(i)) ,propertyInfo 始終是null值,比如SELECT UserName,UserAge FROM USER_TEST WHERE USERID=$USERID,SQL SERVER 執(zhí)行的時(shí)候調(diào)試可以看到dr.GetName(0)是UserName,dr.GetName(1)是UserAge,ORACLE執(zhí)行解析就變了,全是大寫了,變成了USERNAE,USERAGE,這么一來和找不到UserInfo類的屬性了,因?yàn)閁serInfo類的屬性是 UserName,和UserAge,C#語言變量也是區(qū)分大小寫的嘛,當(dāng)然就找不到了,所以propertyInfo就為null了,故在這里再次建議大家在數(shù)據(jù)庫設(shè)計(jì)和程序字段屬性設(shè)計(jì)時(shí)采用大寫標(biāo)準(zhǔn)(如果不涉及多數(shù)據(jù)庫當(dāng)然也不需要這么做)。
最后說下測(cè)試調(diào)用代碼,首先webconfig配置里面這樣配置下,主要選取SQL SERVER和ORACLE做測(cè)試,畢竟這是.NET支持的兩個(gè)典型數(shù)據(jù)庫,要是把.NET所支持的所有書庫都測(cè)試一遍,那測(cè)試量可不小了,呵呵。

復(fù)制代碼 代碼如下:

<connectionStrings>
<add name="ConnStr" connectionString="uid=sa;pwd=peace;database=TEST;server=." providerName="System.Data.SqlClient" />
<!--<add name="ConnStr" connectionString="server=.;data source=peace;user id=cct;password=cct;enlist=true" providerName="System.Data.OracleClient"/>-->
</connectionStrings>


protected void Page_Load(object sender, EventArgs e)
{
//測(cè)試DataReader,SQLSERVER和ORACLE都通過
//DataProviderFactory fac = new DataProviderFactory();
//DbParameterCollection ParaCollect = fac.GetParmCollection();
//fac.AddParam("USERID", 100, ParaCollect);
//DbDataReader dr = fac.ExecuteDataReader(fac.conn, "SELECT * FROM USER_TEST WHERE USERID=$USERID");
//while (dr.Read())
//{
// string a = dr[1].ToString();
//}
//fac.conn.Close();//在調(diào)用處顯示關(guān)閉

//無參數(shù)DataSet測(cè)試 SQLSERVER和ORACLE都通過
//DataTable dt = fac.ExecDataSet("SELECT * FROM USER_TEST").Tables[0];
//帶參數(shù)DataSet測(cè)試 SQLSERVER和ORACLE都通過
//DbParameterCollection ParaCollect = fac.GetParmCollection();
//fac.AddParam("USERID", 100, ParaCollect);
//fac.AddParam("USERNAME", "局%", ParaCollect);//這里的參數(shù)名可以任意成其它,不一定非要和字段名相同(下同)
//DataTable dt = fac.ExecDataSet("SELECT * FROM USER_TEST WHERE USERNAME LIKE $USERNAME").Tables[0];
//DataTable dt = fac.ExecDataSet("SELECT * FROM USER_TEST WHERE USERID=$USERID OR USERNAME LIKE $USERNAME").Tables[0];//多參數(shù)測(cè)試
//單值測(cè)試(帶參數(shù)) SQLSERVER和ORACLE都通過
//DbParameterCollection ParaCollect = fac.GetParmCollection();
//fac.AddParam("USERID", 100, ParaCollect);
//string retValue = fac.ReturnValue("SELECT USERNAME FROM USER_TEST WHERE USERID=$USERID");
//帶參存儲(chǔ)過程測(cè)試返回結(jié)果集 SQLSERVER和ORACLE都通過
//DbParameterCollection ParaCollect = fac.GetParmCollection();
//fac.AddParam("StartDate", "2009-8-1", ParaCollect);
//fac.AddParam("EndDate", "2009-8-21", ParaCollect);
//DataTable dt = fac.RunProcedure("USP_GetMixedReport").Tables[0];

//帶參數(shù)測(cè)試存儲(chǔ)過程的輸出參數(shù)值和返回值,方法不返回結(jié)果集 SQLSERVER通過
//int flag = 0, sign = 0, ret = 0;
//DbParameterCollection ParaCollect = fac.GetParmCollection();
//fac.AddParam("USER_ACCOUNT", DbType.String, "admin", ParaCollect);
//fac.AddParam("USER_PWD", DbType.String, "68053af2923e00204c3ca7c6a3150cf7", ParaCollect);
//fac.AddParam("FLAG", DbType.Int32, "", ParaCollect);
//ParaCollect["@FLAG"].Direction = System.Data.ParameterDirection.Output;
//fac.AddParam("SIGN", DbType.Int32, "", ParaCollect);
//ParaCollect["@SIGN"].Direction = System.Data.ParameterDirection.Output;
//fac.AddParam("RetValue", DbType.String, "", ParaCollect);
//ParaCollect["@RetValue"].Direction = System.Data.ParameterDirection.ReturnValue;
//fac.RunVoidProcedure("SP_ValideLogin");
//flag = int.Parse(ParaCollect["@FLAG"].Value.ToString());
//sign = int.Parse(ParaCollect["@SIGN"].Value.ToString());
//ret = int.Parse(ParaCollect["@RetValue"].Value.ToString());//存儲(chǔ)過程約定返回值必須是int型

//改進(jìn)后帶參數(shù)測(cè)試存儲(chǔ)過程的輸出參數(shù)值和返回值的測(cè)試 SQLSERVER和ORACLE都通過
//int flag = 0, sign = 0, ret = 0;
//DataProviderFactory fac = new DataProviderFactory();
//DbParameterCollection ParaCollect = fac.GetParmCollection();
//fac.AddInputParam("USER_ACCOUNT", "admin", ParaCollect);
//fac.AddInputParam("USER_PWD", "68053af2923e00204c3ca7c6a3150cf7", ParaCollect);
//fac.AddOutputParam("FLAG", ParaCollect);
//fac.AddOutputParam("SIGN", ParaCollect);
//fac.AddReturnParam("RetValue", ParaCollect);
//fac.RunVoidProcedure("SP_ValideLogin");
//string prefix = fac.retParaformat.Replace(":","");//Oracle存儲(chǔ)過程參數(shù)前冒號(hào)移除掉
//flag = int.Parse(ParaCollect[string.Format(prefix,"FLAG")].Value.ToString());
//sign = int.Parse(ParaCollect[string.Format(prefix, "SIGN")].Value.ToString());
//ret = int.Parse(ParaCollect[string.Format(prefix, "RetValue")].Value.ToString());//存儲(chǔ)過程約定返回值必須是int型

//調(diào)用存儲(chǔ)過程測(cè)試 SQLSERVER和ORACLE都通通過
//DataProviderFactory fac = new DataProviderFactory();
//DbParameterCollection ParaCollect = fac.GetParmCollection();
//fac.AddInputParam("P_UserID", 7, ParaCollect);
//fac.AddInputParam("P_UserName", "peace", ParaCollect);
//fac.AddInputParam("P_UserAge", 100, ParaCollect);
//fac.RunVoidProcedure("PROC_USER_TEST_ADD");
//多條提交事務(wù)處理測(cè)試 SQLSERVER和ORACLE都通過
//List<string> SqlList = new List<string>();
//DataProviderFactory fac = new DataProviderFactory();
//DbParameterCollection ParaCollect = fac.GetParmCollection();
//fac.AddParam("UserName", "peaceli", ParaCollect);
//fac.AddParam("UserAge", 150, ParaCollect);
//SqlList.Add("INSERT INTO USER_TEST(UserName,UserAge) VALUES($UserName,$UserAge)");
//SqlList.Add("INSERT INTO USER_TEST(UserName,UserAge) VALUES($UserName,$UserAge)");
//SqlList.Add("INSERT INTO USER_TEST(UserName,UserAge) VALUES($UserName,$UserAge)");
//fac.ExecSqlTran(SqlList);
//插入操作參數(shù)測(cè)試(SQL SERVER) 通過
//UserInfo ui = new UserInfo();
//ui.UserName = "hello peace";
//ui.UserAge = 100;
//Addinn(ui);
//插入操作參數(shù)測(cè)試(Oracle) 通過
//UserInfo ui = new UserInfo();
//ui.USERID = 10;
//ui.USERNAME = "hello peace";
//ui.USERAGE = 120;
//Addin(ui);
//插入操作反射參數(shù)轉(zhuǎn)換測(cè)試 SQLSERVER和ORACLE都通過
//UserInfo ui = new UserInfo();
//ui.USERNAME = "peaceli";
//ui.USERAGE = 110;
//Add(ui);
//返回實(shí)體對(duì)象測(cè)試 SQLSERVER和ORACLE都通過
UserInfo ui = new UserInfo();
ui.USERID = 1;
GetInfo(ui);
}
//private void Addinn(UserInfo ui)
//{
// DataProviderFactory fac = new DataProviderFactory();
// DbParameterCollection ParaCollect = fac.GetParmCollection();
// fac.AddParam("@UserName", ui.UserName, ParaCollect);
// fac.AddParam("@UserAge", ui.UserAge, ParaCollect);
// fac.ExecSql("INSERT INTO USER_TEST(UserName,UserAge) VALUES(@UserName,@UserAge)");
//}
private void Addin(UserInfo ui)
{
DataProviderFactory fac = new DataProviderFactory();
DbParameterCollection ParaCollect = fac.GetParmCollection();
//fac.AddParam(":UserName", ui.UserName, ParaCollect);//給參數(shù)賦值時(shí)冒號(hào)可以不加,但有的版本可能必須加
//fac.AddParam(":UserAge", ui.UserAge, ParaCollect);
//fac.AddParam("UserID", ui.USERID, ParaCollect); //這行注釋放開在ORACLE下同不過,ORACLE要求所全參數(shù)匹配,有多余參數(shù)就不行,這點(diǎn)有些變態(tài)
fac.AddParam("UserName", ui.USERNAME, ParaCollect);//SQL SERVER只要求用到的參數(shù)包含在參數(shù)集合里就行了,其它多余參數(shù)并不影響執(zhí)行
fac.AddParam("UserAge", ui.USERAGE, ParaCollect);
fac.ExecSql("INSERT INTO USER_TEST(UserName,UserAge) VALUES(:UserName,:UserAge)");
}
private void Add(UserInfo ui)
{
DataProviderFactory fac = new DataProviderFactory();
DbParameterCollection ParaCollect = fac.GetParmCollection();
string[] fields = { "USERNAME", "USERAGE" };//要求參數(shù)化的實(shí)體屬性
List<string> ListFields = new List<string>(fields);
fac.ConvertToParameters(ui, ParaCollect, ListFields);//如果新增記錄有很多參數(shù)的話,可能AddParam很多次,采用反射批量轉(zhuǎn)換
fac.ExecSql("INSERT INTO USER_TEST(USERNAME,USERAGE) VALUES($USERNAME,$USERAGE)");
}
private void GetInfo(UserInfo ui)
{
DataProviderFactory fac = new DataProviderFactory();
DbParameterCollection ParaCollect = fac.GetParmCollection();
fac.AddParam("USERID", ui.USERID, ParaCollect);
fac.GetModel(ui, "SELECT USERNAME,USERAGE FROM USER_TEST WHERE USERID=$USERID");
}
}

UserInfo類如下:

復(fù)制代碼 代碼如下:

public class UserInfo
{
public int USERID { get; set; }
public string USERNAME { get; set; }
public int USERAGE { get; set; }
}

測(cè)試到最后類屬性改動(dòng)過,統(tǒng)一改成了大寫,再次建議大寫標(biāo)準(zhǔn)(包括數(shù)據(jù)庫設(shè)計(jì)),可以定義成USER_ID,USER_NAME,USER_AGE等,并與數(shù)據(jù)庫字段名保持一致,這樣有利于多數(shù)據(jù)庫的
兼容。
結(jié)語:個(gè)人并不反對(duì)項(xiàng)目里單獨(dú)用對(duì)應(yīng)的xxhelper.cs,某個(gè)項(xiàng)目用SQLSERVER數(shù)據(jù)庫,就用SqlHelper.csL類,ORACLE就用OracleHelper.cs類,這樣來得更干脆快捷,基本上每個(gè)項(xiàng)目都是這對(duì)特定的數(shù)據(jù)庫在開發(fā),沒必要搞成通用類,真要搞成通用類,要經(jīng)過大量的實(shí)際測(cè)試,也許我最近有時(shí)寂寞空虛也無聊,突然想測(cè)試下同時(shí)也想改進(jìn)下,呵呵,零零碎碎花了點(diǎn)時(shí)間測(cè)試了下,選取兩個(gè)數(shù)據(jù)庫測(cè)試了一遍,最終只需要改動(dòng)config配置的數(shù)據(jù)庫連接就可以了,真正達(dá)到了一套系統(tǒng)的無縫切換。里面有些可能還說的不夠準(zhǔn)確,可能也還有遺漏的地方,僅供參考吧?。?!
訪問類庫的文件完整的貼一次,如下:

復(fù)制代碼 代碼如下:

//*****************************************************************************************************************
//* 編寫人 :peace
//* EMAIL : peacechzh@126.com
//* 開發(fā)日期:2009-10-21
//* 修 改 人:
//* 修改日期:
//* 描 述:數(shù)據(jù)庫工廠訪問類
//* 更新描述:里面供調(diào)用執(zhí)行的各方法可帶參數(shù)執(zhí)行,在外部指定參數(shù)名和參數(shù)值即可。
//* 最終期望:支持.NET所支持的所有數(shù)據(jù)庫并達(dá)到系統(tǒng)的無縫切換(盡情的忽悠吧O(∩_∩)O~)
//*****************************************************************************************************************
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Configuration;
using System.Reflection;
namespace DataProvider
{
public class DataProviderFactory
{
public DbConnection conn;//抽象類型
private DbCommand cmd;//抽象類型
private DbProviderFactory provider;
private DbParameter Para;//不同數(shù)據(jù)庫參數(shù)類型的抽象類型
private DbDataAdapter Adapter;//對(duì)應(yīng)不同數(shù)據(jù)庫的數(shù)據(jù)適配器
Dictionary<Type, String> ParametersFormat;//不同數(shù)據(jù)庫參數(shù)格式化類型
public string retParaformat = string.Empty;//最終返回的格式化標(biāo)志,如@{0},:{0}
public DataProviderFactory()
{
//從配置文件中取出標(biāo)示數(shù)據(jù)庫類型的字符串并通過ProviderName的不同支持不同類型的數(shù)據(jù)庫
string providerName = ConfigurationManager.ConnectionStrings["ConnStr"].ProviderName;//也可以用索引,從1開始
//創(chuàng)建一個(gè)數(shù)據(jù)庫對(duì)應(yīng)的實(shí)例,使用該實(shí)例就可以創(chuàng)建對(duì)應(yīng)的connection,command 和adapater等等對(duì)象
provider = DbProviderFactories.GetFactory(providerName);
//創(chuàng)建具體的數(shù)據(jù)庫連接類型和命令執(zhí)行類型
conn = provider.CreateConnection();
conn.ConnectionString = ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString;
cmd = provider.CreateCommand();
cmd.Connection = conn;
//創(chuàng)建具體的參數(shù)類型
Para = provider.CreateParameter();
//創(chuàng)建具體的適配器類型
Adapter = provider.CreateDataAdapter();
//不同數(shù)據(jù)庫參數(shù)前綴格式化
ParametersFormat = new Dictionary<Type, String>();
ParametersFormat.Add(typeof(System.Data.SqlClient.SqlCommand), "@{0}");//因SQL SERVER只返回{0}沒有@前綴,在此初始化處理
//返回格式化標(biāo)志
retParaformat = GetParameterFormat(cmd);
}
/// <summary>
/// 添加參數(shù)
/// </summary>
/// <param name="ParaName">參數(shù)名稱</param>
/// <param name="SqlType">參數(shù)數(shù)據(jù)類型</param>
/// <param name="ParaValue">參數(shù)值</param>
/// <param name="ParaCollect">參數(shù)對(duì)象的集合</param>
public void AddParam(string ParaName, DbType SqlType, object ParaValue, DbParameterCollection ParaCollect)
{
//不允許將一個(gè)DbCommand對(duì)象的Parameters插入到另外一個(gè)DbCommand對(duì)象,那么多個(gè)參數(shù)的話可以加上下面一句判斷
//如果已經(jīng)存在至少一個(gè)對(duì)象時(shí),再深層拷貝一個(gè)
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat, ParaName);
Para.DbType = SqlType;
if (ParaValue == null)
{
Para.Value = string.Empty;//DBNull.Value;
}
else
{
Para.Value = ParaValue;
}
ParaCollect.Add(Para);
}
public void AddParam(string ParaName, object ParaValue, DbParameterCollection ParaCollect)
{
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat, ParaName);//將參數(shù)格式化為具體的數(shù)據(jù)庫參數(shù)格式
if (ParaValue == null)
{
Para.Value = string.Empty;
}
else
{
Para.Value = ParaValue;
}
ParaCollect.Add(Para);
}
/// <summary>
/// 存儲(chǔ)過程輸入?yún)?shù)
/// </summary>
/// <param name="ParaName"></param>
/// <param name="ParaValue"></param>
/// <param name="ParaCollect"></param>
public void AddInputParam(string ParaName, object ParaValue, DbParameterCollection ParaCollect)
{
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat.Replace(":",""), ParaName);//ORACLE存儲(chǔ)過程參數(shù)前沒有冒號(hào)
if (ParaValue == null)
{
Para.Value = string.Empty;
}
else
{
Para.Value = ParaValue;
}
ParaCollect.Add(Para);
}
/// <summary>
/// 存儲(chǔ)過程輸出參數(shù)
/// </summary>
/// <param name="ParaName"></param>
/// <param name="ParaValue"></param>
/// <param name="ParaCollect"></param>
public void AddOutputParam(string ParaName, DbParameterCollection ParaCollect)
{
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat.Replace(":", ""), ParaName);
Para.Value = string.Empty;
ParaCollect.Add(Para);
ParaCollect[Para.ParameterName].Direction = System.Data.ParameterDirection.Output;//指定該參數(shù)為輸出參數(shù)
}
/// <summary>
/// 存儲(chǔ)過程返回值參數(shù)
/// </summary>
/// <param name="ParaName"></param>
/// <param name="ParaValue"></param>
/// <param name="ParaCollect"></param>
public void AddReturnParam(string ParaName,DbParameterCollection ParaCollect)
{
if (ParaCollect.Count >= 1)
{
Para = (DbParameter)((ICloneable)ParaCollect[0]).Clone();
}
Para.ParameterName = string.Format(retParaformat.Replace(":", ""), ParaName);
Para.Value = string.Empty;
ParaCollect.Add(Para);
ParaCollect[Para.ParameterName].Direction = System.Data.ParameterDirection.ReturnValue;//指定該參數(shù)為返回值參數(shù)
}
/// <summary>
/// 抽象參數(shù)集合類型
/// </summary>
/// <returns></returns>
public DbParameterCollection GetParmCollection()
{
return cmd.Parameters;
}
/// <summary>
/// 執(zhí)行SQL并返回?cái)?shù)據(jù)集
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public DataSet ExecDataSet(string Sql)
{
DataSet ds = new DataSet();
try
{
this.Open();
cmd.CommandText = Replace(Sql);
Adapter.SelectCommand = cmd;
Adapter.Fill(ds);
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}
return ds;
}
/// <summary>
/// 執(zhí)行SQL語句并返回DataReader對(duì)象
/// </summary>
/// <param name="dbcon"></param>
/// <param name="cmdText"></param>
/// <returns></returns>
public DbDataReader ExecuteDataReader(DbConnection dbcon,string cmdText)
{
try
{
if (dbcon.State == ConnectionState.Closed)
{
dbcon.Open();
}
cmd.CommandText = Replace(cmdText);
DbDataReader dr = cmd.ExecuteReader();
cmd.Parameters.Clear();
cmd.Dispose();
return dr;
}
catch
{
dbcon.Close();//發(fā)生異常在此處關(guān)閉,否則在調(diào)用顯式處關(guān)閉
return null;
}
}

/// <summary>
/// 判斷記錄是否存在
/// </summary>
/// <param name="Sql"></param>
/// <returns></returns>
public bool Exist(string Sql)
{
bool exist;
this.Open();
cmd.CommandText = Replace(Sql);
DbDataReader dr = cmd.ExecuteReader();
if (dr.HasRows)
{
exist = true; //記錄存在
}
else
{
exist = false; //記錄不存在
}
dr.Close();
this.Close();
return exist;
}
/// <summary>
/// 執(zhí)行SQL語句
/// </summary>
/// <param name="sql"></param>
public void ExecSql(string Sql)
{
try
{
this.Open();
cmd.CommandText = Replace(Sql);
cmd.ExecuteNonQuery();
cmd.Dispose();
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}

}
/// <summary>
/// 執(zhí)行SQL語句,返回一個(gè)單值
/// </summary>
/// <param name="sql"></param>
/// <returns></returns>
public string ReturnValue(string Sql)
{
object returnValue = string.Empty;
try
{
this.Open();
cmd.CommandText = Replace(Sql);
returnValue = cmd.ExecuteScalar();
if (returnValue == null)
{
returnValue = string.Empty;
}
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}
return returnValue.ToString();
}
/// <summary>
/// 執(zhí)行多條SQL語句并啟用數(shù)據(jù)庫事務(wù)
/// </summary>
/// <param name="SQLStringList"></param>
public bool ExecSqlTran(List<String> SQLStringList)
{
this.Open();
DbTransaction trans = conn.BeginTransaction();
cmd.Transaction = trans;
try
{
for (int n = 0; n < SQLStringList.Count; n++)
{
cmd.CommandText = Replace(SQLStringList[n]);
cmd.ExecuteNonQuery();
}
trans.Commit();
return true;
}
catch
{
trans.Rollback();
return false;
}
finally
{
this.Close();
}
}

/// <summary>
/// 執(zhí)行存儲(chǔ)過程并返回結(jié)果集
/// </summary>
/// <param name="storedProcName">存儲(chǔ)過程名</param>
/// <returns>DataSet</returns>
public DataSet RunProcedure(string storedProcName)
{
DataSet ds = new DataSet();
try
{
this.Open();
cmd.CommandText = storedProcName;
cmd.CommandType = CommandType.StoredProcedure;
Adapter.SelectCommand = cmd;
//Adapter.SelectCommand.CommandTimeout = 1200;//可以設(shè)置適當(dāng)?shù)某瑫r(shí)時(shí)間(秒),避免選擇時(shí)間段過大導(dǎo)致填充數(shù)據(jù)集超時(shí)
Adapter.Fill(ds);
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}
return ds;
}
/// <summary>
/// 執(zhí)行存儲(chǔ)過程,方法不返回結(jié)果集
/// </summary>
/// <param name="storedProcName"></param>
public void RunVoidProcedure(string storedProcName)
{
cmd.CommandText = storedProcName;
cmd.CommandType = CommandType.StoredProcedure;
try
{
this.Open();
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
this.Close();
}
}

/// <summary>
/// 將實(shí)體類的屬性進(jìn)行參數(shù)轉(zhuǎn)換(ORACLE測(cè)試通不過,必須要求所有參數(shù)都包含在語句中才行)
/// </summary>
/// <param name="model"></param>
/// <param name="ParaCollect"></param>
//public void ConvertToParameters(object model, DbParameterCollection ParaCollect)
//{
// Type T = model.GetType();
// PropertyInfo[] propert = T.GetProperties();
// for (int i = 0; i < propert.Length; i++)
// {
// AddParam(propert[i].Name, propert[i].GetValue(model, null), ParaCollect);
// }
//}
/// <summary>
/// 將實(shí)體類的屬性進(jìn)行參數(shù)轉(zhuǎn)換
/// </summary>
/// <param name="model"></param>
/// <param name="ParaCollect"></param>
public void ConvertToParameters(object model, DbParameterCollection ParaCollect,List<string> fields)
{
Type T = model.GetType();
PropertyInfo[] propert = T.GetProperties();
for (int i = 0; i < propert.Length; i++)
{
if (fields.Contains(propert[i].Name)) //檢測(cè)必須參數(shù)化的實(shí)體屬性
{
AddParam(propert[i].Name, propert[i].GetValue(model, null), ParaCollect);
}
}
}

/// <summary>
/// 通過反射將取出的數(shù)據(jù)寫入實(shí)體類(ORACLE測(cè)試通不過,需進(jìn)行類型強(qiáng)制轉(zhuǎn)換)
/// </summary>
/// <param name="model"></param>
/// <param name="cmdText"></param>
//public void GetModel(object model, string cmdText)
//{
// PropertyInfo propertyInfo;
// DbDataReader dr = ExecuteDataReader(conn, cmdText);
// while (dr.Read())
// {
// for (int i = 0; i < dr.FieldCount; i++)
// {
// propertyInfo = model.GetType().GetProperty(dr.GetName(i));
// if (propertyInfo != null)
// {
// if (dr.GetValue(i) != DBNull.Value)
// {
// //Type t = dr.GetValue(i).GetType();
// propertyInfo.SetValue(model, dr.GetValue(i), null);
// }
// }
// }
// }
// dr.Close();
// conn.Close();
//}
/// <summary>
/// 通過反射將數(shù)據(jù)綁定到實(shí)體對(duì)象,由于不同數(shù)據(jù)庫對(duì)應(yīng)于.NET的數(shù)據(jù)類型不一樣
/// 需做強(qiáng)制類型轉(zhuǎn)換
/// </summary>
/// <param name="model"></param>
/// <param name="cmdText"></param>
public void GetModel(object model, string cmdText)
{
PropertyInfo propertyInfo;
DbDataReader dr = ExecuteDataReader(conn, cmdText);
object _value;
while (dr.Read())
{
for (int i = 0; i < dr.FieldCount; i++)
{
propertyInfo = model.GetType().GetProperty(dr.GetName(i));
if (propertyInfo != null && dr.GetValue(i) != DBNull.Value)
{
switch (propertyInfo.PropertyType.ToString())
{
case "System.String":
{
_value = Convert.ToString(dr.GetValue(i));//字符串是全球通用類型,也可以不用轉(zhuǎn)換
propertyInfo.SetValue(model, _value, null);
}break;
case "System.Int32":
{
_value = Convert.ToInt32(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
case "System.Single":
{
_value = Convert.ToSingle(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
case "System.Decimal":
{
_value = Convert.ToDecimal(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
case "System.Double":
{
_value = Convert.ToDouble(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
case "":
{
_value = Convert.ToDateTime(dr.GetValue(i));
propertyInfo.SetValue(model, _value, null);
} break;
default: break;
}
}
}
}
dr.Close();
conn.Close();
}
/// <summary>
/// 根據(jù)不同的數(shù)據(jù)庫命令對(duì)象返回該類型數(shù)據(jù)庫參數(shù)的前綴格式化字符串
/// </summary>
/// <param name="command"></param>
/// <returns></returns>
private string GetParameterFormat(DbCommand command)
{
if (!ParametersFormat.ContainsKey(command.GetType()))
{
this.Open();//讀取參數(shù)前綴時(shí)需打開數(shù)據(jù)庫連接
ParametersFormat.Add(
command.GetType(),
command.Connection.GetSchema("DataSourceInformation")
.Rows[0]["ParameterMarkerFormat"].ToString());
//conn.Close();在真正執(zhí)行語句的時(shí)候去關(guān)閉,避免重復(fù)打開
}
return ParametersFormat[command.GetType()];
}
private void Open()
{
if (conn.State == ConnectionState.Closed)
{
conn.Open();
}
}
private void Close()
{
if (conn.State == ConnectionState.Open)
{
conn.Close();
}
}
/// <summary>
/// 替換DML語句里的參數(shù)前綴
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string Replace(string str)
{
return str.Replace("$", retParaformat.Substring(0, 1));
}
}
}

文件下載:PeaceHelper.cs

相關(guān)文章

最新評(píng)論