• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

    告別ADO.NET實現應用系統無縫切換的煩惱(總結篇)

    來源:懂視網 責編:小采 時間:2020-11-27 22:44:02
    文檔

    告別ADO.NET實現應用系統無縫切換的煩惱(總結篇)

    告別ADO.NET實現應用系統無縫切換的煩惱(總結篇):可能只是那么想也是那么設計的,要支持多數據庫,要能支持多數據庫,萬一要是以后數據庫變了怎么辦?萬一要是。怎么辦?這些顧慮很多時候是不必要的,反而繞了彎子。大都是做項目應用系統而非產品,即使要用不同的數據庫了,基本上是吧上一個項目全COPY
    推薦度:
    導讀告別ADO.NET實現應用系統無縫切換的煩惱(總結篇):可能只是那么想也是那么設計的,要支持多數據庫,要能支持多數據庫,萬一要是以后數據庫變了怎么辦?萬一要是。怎么辦?這些顧慮很多時候是不必要的,反而繞了彎子。大都是做項目應用系統而非產品,即使要用不同的數據庫了,基本上是吧上一個項目全COPY

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

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

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

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

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

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

    添加參數的方法如下:
    代碼如下:

    /// <summary>
    /// 添加參數
    /// </summary>
    /// <param name="ParaName">參數名稱</param>
    /// <param name="SqlType">參數數據類型</param>
    /// <param name="ParaValue">參數值</param>
    /// <param name="ParaCollect">參數對象的集合</param>
    public void AddParam(string ParaName, DbType SqlType, object ParaValue, DbParameterCollection ParaCollect)
    {
    //不允許將一個DbCommand對象的Parameters插入到另外一個DbCommand對象,那么多個參數的話可以加上下面一句判斷
    //如果已經存在至少一個對象時,再深層拷貝一個
    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);
    }

    上面有句判斷,如果有多個參數會出異常,網上搜了下,注釋就是網上的解釋,不多說了,意思很清楚。這個方法里還有一點,如果DbType參數不要的話測試也是可以通過的,猜想如果不顯示指定參數數據類型的話,是不是都默認為object類型?這樣的話會不會涉及一個裝拆箱的操作呢?但是開發人員在調用處添加參數,是不應該關心參數的數據類型才對,干脆數據類型參數不要了,改成如下方法了:
    代碼如下:

    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);//將參數格式化為具體的數據庫參數格式
    if (ParaValue == null)
    {
    Para.Value = string.Empty;
    }
    else
    {
    Para.Value = ParaValue;
    }
    ParaCollect.Add(Para);
    }

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

    /// <summary>
    /// 存儲過程輸入參數
    /// </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存儲過程參數前沒有冒號
    if (ParaValue == null)
    {
    Para.Value = string.Empty;
    }
    else
    {
    Para.Value = ParaValue;
    }
    ParaCollect.Add(Para);
    }
    /// <summary>
    /// 存儲過程
    輸出參數
    /// </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;//指定該參數為輸出參數
    }
    /// <summary>
    /// 存儲過程返回值參數
    /// </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;//指定該參數為返回值參數
    }

    OK,現在開始說下peacehelper.cs里的八大方法(其實算起來應該是10個),應該來說涵蓋絕大多應該系統操作數據庫的絕大部分功能,如果有特殊的操作可以在此基礎上添加。
    第一個,大家都熟悉的返回結果集:
    代碼如下:

    /// <summary>
    /// 執行SQL并返回數據集
    /// </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;
    }

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

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

    因為不同數據庫除了在添加參數時有前綴的區別,再具體執行語句時也有前綴區別嘛,比如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,在此就需要統一一個前綴規則了,統一這樣SELECT USER_NAME,USER_AGE FROM USERS WHERE USER_ID=$USER_ID,在執行前根據不同數據庫替換前綴$符號,當然這個約定規則不一定是最完美的,也許還存在一定的問題,寫到這我也突然想起來之前我見過別人
    的系統中有的就是變量參數用的這種類似特殊符號,肯定也是為了兼容多數據庫所作的處理了,呵呵,具體的調用及測試之后統一說明。還有幾個方法也和上面類似,大家都熟悉的。如下(不再做具體解釋了):
    代碼如下:

    /// <summary>
    /// 執行SQL語句并返回DataReader對象
    /// </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();//發生異常在此處關閉,否則在調用顯式處關閉
    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>
    /// 執行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>
    /// 執行SQL語句,返回一個單值
    /// </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>
    /// 執行多條SQL語句并啟用數據庫事務
    /// </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();
    }
    }

    下面說下兩個存儲過程,存儲過程基本上分兩種,返回結果集的存儲過程和執行業務邏輯不返回結果集但卻有返回值(如標志等),對于需要有返回值的存儲過程,我個人趨向于用

    輸出
    參數代替返回值,因為都能達到一樣的效果目的,而且輸出參數可以有多個,也就可以根據需要能有多個所謂的“返回值”,所以我之前的開發中一直是用output參數來代替return參數。

    代碼如下:


    /// <summary>
    /// 執行存儲過程并返回結果集
    /// </summary>
    /// <param name="storedProcName">存儲過程名</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;//可以設置適當的超時時間(秒),避免選擇時間段過大導致填充數據集超時
    Adapter.Fill(ds);
    }
    catch (Exception ex)
    {
    throw ex;
    }
    finally
    {
    this.Close();
    }
    return ds;
    }
    /// <summary>
    /// 執行存儲過程,方法不返回結果集
    /// </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>
    /// 將實體類的屬性進行參數轉換(ORACLE測試通不過,必須要求所有參數都包含在語句中才行)
    /// </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>
    /// 將實體類的屬性進行參數轉換
    /// </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)) //檢測必須參數化的實體屬性
    {
    AddParam(propert[i].Name, propert[i].GetValue(model, null), ParaCollect);
    }
    }
    }

    /// <summary>
    /// 通過反射將取出的數據寫入實體類(ORACLE測試通不過,需進行類型強制轉換)
    /// </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>
    /// 通過反射將數據綁定到實體對象,由于不同數據庫對應于.NET的數據類型不一樣
    /// 需做強制類型轉換
    /// </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));//字符串是全球通用類型,也可以不用轉換
    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();
    }

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

    代碼如下:


    <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)
    {
    //測試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();//在調用處顯示關閉

    //無參數DataSet測試 SQLSERVER和ORACLE都通過
    //DataTable dt = fac.ExecDataSet("SELECT * FROM USER_TEST").Tables[0];
    //帶參數DataSet測試 SQLSERVER和ORACLE都通過
    //DbParameterCollection ParaCollect = fac.GetParmCollection();
    //fac.AddParam("USERID", 100, ParaCollect);
    //fac.AddParam("USERNAME", "局%", ParaCollect);//這里的參數名可以任意成其它,不一定非要和字段名相同(下同)
    //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];//多參數測試
    //單值測試(帶參數) SQLSERVER和ORACLE都通過
    //DbParameterCollection ParaCollect = fac.GetParmCollection();
    //fac.AddParam("USERID", 100, ParaCollect);
    //string retValue = fac.ReturnValue("SELECT USERNAME FROM USER_TEST WHERE USERID=$USERID");
    //帶參存儲過程測試返回結果集 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];

    //帶參數測試存儲過程的

    輸出參數值和返回值,方法不返回結果集 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());//存儲過程約定返回值必須是int型

    //改進后帶參數測試存儲過程的輸出參數值和返回值的測試 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存儲過程參數前冒號移除掉
    //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());//存儲過程約定返回值必須是int型

    //調用存儲過程測試 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");
    //多條提交事務處理測試 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);
    //插入操作參數測試(SQL SERVER) 通過
    //UserInfo ui = new UserInfo();
    //ui.UserName = "hello peace";
    //ui.UserAge = 100;
    //Addinn(ui);
    //插入操作參數測試(Oracle) 通過
    //UserInfo ui = new UserInfo();
    //ui.USERID = 10;
    //ui.USERNAME = "hello peace";
    //ui.USERAGE = 120;
    //Addin(ui);
    //插入操作反射參數轉換測試 SQLSERVER和ORACLE都通過
    //UserInfo ui = new UserInfo();
    //ui.USERNAME = "peaceli";
    //ui.USERAGE = 110;
    //Add(ui);
    //返回實體對象測試 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);//給參數賦值時冒號可以不加,但有的版本可能必須加
    //fac.AddParam(":UserAge", ui.UserAge, ParaCollect);
    //fac.AddParam("UserID", ui.USERID, ParaCollect); //這行注釋放開在ORACLE下同不過,ORACLE要求所全參數匹配,有多余參數就不行,這點有些變態
    fac.AddParam("UserName", ui.USERNAME, ParaCollect);//SQL SERVER只要求用到的參數包含在參數集合里就行了,其它多余參數并不影響執行
    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" };//要求參數化的實體屬性
    List<string> ListFields = new List<string>(fields);
    fac.ConvertToParameters(ui, ParaCollect, ListFields);//如果新增記錄有很多參數的話,可能AddParam很多次,采用反射批量轉換
    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類如下:

    代碼如下:


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

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

    代碼如下:


    //*****************************************************************************************************************
    //* 編寫人 :peace
    //* EMAIL : peacechzh@126.com
    //* 開發日期:2009-10-21
    //* 修 改 人:
    //* 修改日期:
    //* 描 述:數據庫工廠訪問類
    //* 更新描述:里面供調用執行的各方法可帶參數執行,在外部指定參數名和參數值即可。
    //* 最終期望:支持.NET所支持的所有數據庫并達到系統的無縫切換(盡情的忽悠吧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;//不同數據庫參數類型的抽象類型
    private DbDataAdapter Adapter;//對應不同數據庫的數據適配器
    Dictionary<Type, String> ParametersFormat;//不同數據庫參數格式化類型
    public string retParaformat = string.Empty;//最終返回的格式化標志,如@{0},:{0}
    public DataProviderFactory()
    {
    //從配置文件中取出標示數據庫類型的字符串并通過ProviderName的不同支持不同類型的數據庫
    string providerName = ConfigurationManager.ConnectionStrings["ConnStr"].ProviderName;//也可以用索引,從1開始
    //創建一個數據庫對應的實例,使用該實例就可以創建對應的connection,command 和adapater等等對象
    provider = DbProviderFactories.GetFactory(providerName);
    //創建具體的數據庫連接類型和命令執行類型
    conn = provider.CreateConnection();
    conn.ConnectionString = ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString;
    cmd = provider.CreateCommand();
    cmd.Connection = conn;
    //創建具體的參數類型
    Para = provider.CreateParameter();
    //創建具體的適配器類型
    Adapter = provider.CreateDataAdapter();
    //不同數據庫參數前綴格式化
    ParametersFormat = new Dictionary<Type, String>();
    ParametersFormat.Add(typeof(System.Data.SqlClient.SqlCommand), "@{0}");//因SQL SERVER只返回{0}沒有@前綴,在此初始化處理
    //返回格式化標志
    retParaformat = GetParameterFormat(cmd);
    }
    /// <summary>
    /// 添加參數
    /// </summary>
    /// <param name="ParaName">參數名稱</param>
    /// <param name="SqlType">參數數據類型</param>
    /// <param name="ParaValue">參數值</param>
    /// <param name="ParaCollect">參數對象的集合</param>
    public void AddParam(string ParaName, DbType SqlType, object ParaValue, DbParameterCollection ParaCollect)
    {
    //不允許將一個DbCommand對象的Parameters插入到另外一個DbCommand對象,那么多個參數的話可以加上下面一句判斷
    //如果已經存在至少一個對象時,再深層拷貝一個
    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);//將參數格式化為具體的數據庫參數格式
    if (ParaValue == null)
    {
    Para.Value = string.Empty;
    }
    else
    {
    Para.Value = ParaValue;
    }
    ParaCollect.Add(Para);
    }
    /// <summary>
    /// 存儲過程輸入參數
    /// </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存儲過程參數前沒有冒號
    if (ParaValue == null)
    {
    Para.Value = string.Empty;
    }
    else
    {
    Para.Value = ParaValue;
    }
    ParaCollect.Add(Para);
    }
    /// <summary>
    /// 存儲過程
    輸出參數
    /// </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;//指定該參數為輸出參數
    }
    /// <summary>
    /// 存儲過程返回值參數
    /// </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;//指定該參數為返回值參數
    }
    /// <summary>
    /// 抽象參數集合類型
    /// </summary>
    /// <returns></returns>
    public DbParameterCollection GetParmCollection()
    {
    return cmd.Parameters;
    }
    /// <summary>
    /// 執行SQL并返回數據集
    /// </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>
    /// 執行SQL語句并返回DataReader對象
    /// </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();//發生異常在此處關閉,否則在調用顯式處關閉
    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>
    /// 執行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>
    /// 執行SQL語句,返回一個單值
    /// </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>
    /// 執行多條SQL語句并啟用數據庫事務
    /// </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>
    /// 執行存儲過程并返回結果集
    /// </summary>
    /// <param name="storedProcName">存儲過程名</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;//可以設置適當的超時時間(秒),避免選擇時間段過大導致填充數據集超時
    Adapter.Fill(ds);
    }
    catch (Exception ex)
    {
    throw ex;
    }
    finally
    {
    this.Close();
    }
    return ds;
    }
    /// <summary>
    /// 執行存儲過程,方法不返回結果集
    /// </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>
    /// 將實體類的屬性進行參數轉換(ORACLE測試通不過,必須要求所有參數都包含在語句中才行)
    /// </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>
    /// 將實體類的屬性進行參數轉換
    /// </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)) //檢測必須參數化的實體屬性
    {
    AddParam(propert[i].Name, propert[i].GetValue(model, null), ParaCollect);
    }
    }
    }

    /// <summary>
    /// 通過反射將取出的數據寫入實體類(ORACLE測試通不過,需進行類型強制轉換)
    /// </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>
    /// 通過反射將數據綁定到實體對象,由于不同數據庫對應于.NET的數據類型不一樣
    /// 需做強制類型轉換
    /// </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));//字符串是全球通用類型,也可以不用轉換
    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>
    /// 根據不同的數據庫命令對象返回該類型數據庫參數的前綴格式化字符串
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    private string GetParameterFormat(DbCommand command)
    {
    if (!ParametersFormat.ContainsKey(command.GetType()))
    {
    this.Open();//讀取參數前綴時需打開數據庫連接
    ParametersFormat.Add(
    command.GetType(),
    command.Connection.GetSchema("DataSourceInformation")
    .Rows[0]["ParameterMarkerFormat"].ToString());
    //conn.Close();在真正執行語句的時候去關閉,避免重復打開
    }
    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語句里的參數前綴
    /// </summary>
    /// <param name="str"></param>
    /// <returns></returns>
    public string Replace(string str)
    {
    return str.Replace("$", retParaformat.Substring(0, 1));
    }
    }
    }

    文件下載:PeaceHelper.cs

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    告別ADO.NET實現應用系統無縫切換的煩惱(總結篇)

    告別ADO.NET實現應用系統無縫切換的煩惱(總結篇):可能只是那么想也是那么設計的,要支持多數據庫,要能支持多數據庫,萬一要是以后數據庫變了怎么辦?萬一要是。怎么辦?這些顧慮很多時候是不必要的,反而繞了彎子。大都是做項目應用系統而非產品,即使要用不同的數據庫了,基本上是吧上一個項目全COPY
    推薦度:
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 日韩精品欧美亚洲| 精品国产精品国产偷麻豆| 欧美成人精品网站播放| 国产精品拍天天在线| 久久久久亚洲精品中文字幕| 成人国内精品久久久久影院| 曰韩精品无码一区二区三区| 国産精品久久久久久久| 精品一区二区在线观看| 中文字幕一区二区三区日韩精品| 国产精品成人久久久久三级午夜电影 | 国产精品成人观看视频免费| 亚洲午夜成人精品电影在线观看| 国产精品小黄鸭一区二区三区| 国产成人亚洲精品| 久久亚洲精品成人av无码网站| 欧美成人精品网站播放| 国产一区二区精品久久凹凸| 青青草国产精品| 久久99久久99小草精品免视看 | 久久国产精品99久久久久久老狼| 人妻精品久久无码区| 拍国产乱人伦偷精品视频| 精品91自产拍在线观看| 91精品国产福利在线观看麻豆| 久久99精品久久久久久| 久久99精品久久久久久 | 99精品视频3| 国产亚洲精品a在线无码| 久久精品人人做人人爽电影蜜月 | 久久99精品久久久久久秒播| 性欧洲精品videos| 国产99久久九九精品无码 | 黄床大片免费30分钟国产精品| 9999国产精品欧美久久久久久| 久久99国产精品一区二区| 精品国产第1页| 精品九九人人做人人爱| 国产精品一久久香蕉国产线看| 国产精品欧美久久久天天影视| 国产精品日本欧美一区二区|