Sofire v1.0 開源——快速數據庫訪問模式 Sofire.Data(2)


Sofire Suite 是一套個人從 2009 年 08 月開始着手研發的套件。歷經幾年的不斷優化改進,從最初的 V 套件到 Sofire2011 到目前的 Sofire.v1.0,Sofire 已經經歷了許多項目的考驗,並且出色的完成它的使命。現在,我將這套組件再次重構, 嘗試讓它成為任意平台、框架、套件的的底層首選。秉着開源精神,希望這套組件在博友的討論中不斷成長、成熟。

那么,Sofire.v1.0包含什么內容?

下載地址:Sofire.v1.0-120604

1、數據庫訪問(Sofire.Data)

2、快速動態反射(Sofire.Dynamic)

3、高效簡短的二進制序列化(Sofire.Serialization.BinarySuite)

4、遠程對象模式(Sofire.DataComm.Remote)

5、安全高效Socket(Sofire.DataComm.Net)

6、面向切面(Sofire.AOP)

7、等。由於Sofire v1.0 第一期移植,故而功能暫時尚未全部移植完成。

前文

緊接上篇內容《Sofire v1.0 開源——WinForm/SL/WebForm 的 Remoting(1)》。

本文主要講述 SOFIRE 框架在底層開發中,采用 Sofire.Data 對各種數據庫的操作進行統一使用。它仿佛就是對 ADO.NET 的全面封裝。

當然,Sofire.Data 支持哪些數據庫,關鍵是在於實現,而不是在於“支持不支持”,理論上所有基於 ADO.NET 的數據庫全部支持,而其他數據庫,也有部分支持。

當前所支持的數據庫包括:MSSQL、Oracle、Oracle、DDTekOracle、OleDb 和 SQLite。至於其他的數據庫(如 MySql),由於本人實際項目中並沒使用這些數據庫,所有暫時不支持,如果你想支持其他數據庫,請繼承 Sofire.Data.QueryEngineBase。

框架約定
任何函數具有返回內容
在框架的開發過程中,在所有公共函數,都應具有一個返回描述。例如,在處理某業務的函數,可能有人會這樣寫:
        public DataTable GetTotalReport(string username, DateTime begin, DateTime end)
        {
            //處理過程...
            return new DataTable();
        }

當然,這並不是指責這樣的寫法的好壞,而是建議對函數的返回值進行適當的封裝描述。例如,我可以這樣:

        public Result<DataTable> GetTotalReport(string username, DateTime begin, DateTime end)
        {
            try
            {
                //處理過程...
                return new DataTable();
            }
            catch(Exception ex)
            {
                return ex;
            }
        }

通過這樣的約定,可以明確的告訴函數調用者,這個函數返回一個值,但這個操作函數也可能會返回一個錯誤的內容。

返回描述,是為了更好的處理

當遇到具有返回內容的操作函數時,可以這樣的處理返回結果

        public void Test()
        {
            var r = this.GetTotalReport("a", DateTime.Now, DateTime.Now);
            if(r.IsSucceed)
            {
                DataTable table = r.Value;
            }
            else
            {
                Exception ex = r.Exception;
            }
        }

簡單的代碼,表述了返回值具備了函數操作結果的“正確性”,同時也提供了錯誤的詳細信息。以下是返回結果的接口(IResult):

    /// <summary>
    /// 表示一個結果(接口)。
    /// </summary>
    public interface IResult
    {
        #region Properties

        /// <summary>
        /// 獲取執行時發生的錯誤。
        /// </summary>
        Exception Exception
        {
            get;
        }

        /// <summary>
        /// 獲取一個值,表示執行結果是否為失敗。
        /// </summary>
        bool IsFailed
        {
            get;
        }

        /// <summary>
        /// 獲取一個值,表示執行結果是否為忽略。
        /// </summary>
        bool IsIgnored
        {
            get;
        }

        /// <summary>
        /// 獲取一個值,表示執行結果是否為成功。
        /// </summary>
        bool IsSucceed
        {
            get;
        }

        /// <summary>
        /// 獲取執行的狀態。
        /// </summary>
        ResultState State
        {
            get;
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// 指定錯誤信息,將當前結果切換到失敗的狀態。
        /// </summary>
        void ToFailded(Exception exception);

        /// <summary>
        /// 指定錯誤信息,將當前結果切換到失敗的狀態。
        /// </summary>
        void ToFailded(string exceptionMessage);

        /// <summary>
        /// 將當前結果切換到忽略的狀態。
        /// </summary>
        void ToIgnored();

        /// <summary>
        /// 將當前結果切換到成功的狀態,並且清除結果的錯誤信息。
        /// </summary>
        void ToSuccessed();

        /// <summary>
        /// 指示一個結果,與當前結果進行校驗。如果 <paramref name="result"/> 是一個錯誤結果,那么當前的結果將會轉換為錯誤狀態。否則將會轉換 <paramref name="result"/> 的狀態。
        /// </summary>
        /// <param name="result">比較的結果。</param>
        /// <returns>返回一個值,表示結果是否為成功狀態。</returns>
        bool Checking(Result result);

        #endregion Methods
    }


    /// <summary>
    /// 表示包含一個返回值的結果(接口)。
    /// </summary>
    /// <typeparam name="TValue">返回值的類型。</typeparam>
    public interface IResult<TValue> : IResult
    {
        #region Properties

        /// <summary>
        /// 設置或獲取結果的返回值。若結果不處於成功的狀態,將返回默認值。
        /// </summary>
        TValue Value
        {
            get; set;
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// 將當前結果切換到成功的狀態,並且清除結果的錯誤信息。
        /// </summary>
        /// <param name="value">結果返回的值。</param>
        void ToSuccessed(TValue value);

        /// <summary>
        /// 指示一個結果,與當前結果進行校驗。如果 <paramref name="result"/> 是一個錯誤結果,那么當前的結果將會轉換為錯誤狀態。否則將會轉換 <paramref name="result"/> 的狀態。
        /// </summary>
        /// <param name="result">比較的結果。</param>
        /// <param name="value">狀態為成功時的返回值。</param>
        /// <returns>返回一個值,表示結果是否為成功狀態。</returns>
        bool Checking(Result result, TValue value);

        #endregion Methods
    }

    /// <summary>
    /// 表示包含兩個返回值的結果(接口)。
    /// </summary>
    /// <typeparam name="TValue1">第一個返回值的類型。</typeparam>
    /// <typeparam name="TValue2">第二個返回值的類型。</typeparam>
    public interface IResult<TValue1, TValue2> : IResult
    {
        #region Properties

        /// <summary>
        /// 設置或獲取結果的第一個返回值。若結果不處於成功的狀態,將返回默認值。
        /// </summary>
        TValue1 Value1
        {
            get; set;
        }

        /// <summary>
        /// 設置或獲取結果的第二個返回值。若結果不處於成功的狀態,將返回默認值。
        /// </summary>
        TValue2 Value2
        {
            get; set;
        }

        #endregion Properties

        #region Methods

        /// <summary>
        /// 將當前結果切換到成功的狀態,並且清除結果的錯誤信息。
        /// </summary>
        /// <param name="value1">結果的第一個返回值。</param>
        /// <param name="value2">結果的第二個返回值。</param>
        void ToSuccessed(TValue1 value1, TValue2 value2);

        /// <summary>
        /// 指示一個結果,與當前結果進行校驗。如果 <paramref name="result"/> 是一個錯誤結果,那么當前的結果將會轉換為錯誤狀態。否則將會轉換 <paramref name="result"/> 的狀態。
        /// </summary>
        /// <param name="result">比較的結果。</param>
        /// <param name="value1">狀態為成功時的第一個返回值。</param>
        /// <param name="value2">狀態為成功時的第二個返回值。</param>
        /// <returns>返回一個值,表示結果是否為成功狀態。</returns>
        bool Checking(Result result, TValue1 value1, TValue2 value2);

        #endregion Methods
    }

 

Sofire.Data
數據庫是如何連接的?

Sofire.Data 的所有數據庫實現,都派生於 Sofire.Data.QueryEngineBase,通過簡單的幾個抽象實現,從而達到對數據庫的快速支持。

        public void DataConnect()
        {
            string connectionString = "";
            OracleQuery oracleQuery = new OracleQuery(connectionString); // 微軟已經不建議使用這種方式連接 Oracle
            DDTekOracleQuery oleDbQuery = new DDTekOracleQuery(connectionString);
            MsSqlQuery mssqlQuery = new MsSqlQuery(connectionString);
            OleDbQuery oleDbQuery = new OleDbQuery(connectionString);
            SQLiteQuery sqliteQuery = new SQLiteQuery(connectionString);
            // 派生基類 QueryEngineBase 擴展,可以對更多的數據庫提供支持。
        }
數據庫是如何查詢的?

數據庫的查詢

        public void Execute()
        {
            string connectionString = "";
            int uid = 1;
            DDTekOracleQuery oracleQuery = new DDTekOracleQuery(connectionString);
            TableResult r1 = oracleQuery.ExecuteTable("SELECT * FROM Users WHERE UID=:uid", "uid", uid);
            
            if(r1.IsSucceed)
            {
                DataTable table = r1.Value;
            }

            SqlQuery mssqlQuery = new SqlQuery(connectionString);
            TableResult r2 = mssqlQuery.ExecuteTable("SELECT * FROM Users WHERE UID=@uid", "@uid", uid);
            
            if(r2.IsSucceed)
            {
                DataTable table = r2.Value;
            }
        }

當然,上面的演示代碼僅僅是返回一張表,更多的支持請參考以下圖片

由於今年的工作關系,我對 Oracle 的接觸頻繁,Sofire.Data 中對於 Oracle 的支持,也逐漸成熟中,例如支持多行 ExecuteNoQuery,支持游標參數。

        private Result Test1()
        {
            //“>”符號表示這是一個存儲過程,或程序包
            // PKG_FLOW_NAME.UP_GetFlowNameById 的返回值在於一個游標參數。
            var tableResult = query.ExecuteTable(">PKG_FLOW_NAME.UP_GetFlowNameById"
                , new ExecuteParameter("v_FID", 111, DbType.VarNumeric)
                , query.CreateCursor("c"));

            if(tableResult.IsSucceed)
            {
                Console.WriteLine(tableResult.Value.Rows.Count);
            }
            return tableResult;
        }
        private Result Test2()
        {
            var noQueryResult = query.ExecuteNoQuery(@"begin
            insert into table1 select * from XXX;
            insert into table2 select * from XXX;
            insert into table3 select * from XXX;
            insert into table4 select * from XXX;
            end;");

            if(tableResult.IsSucceed)
            {
                Console.WriteLine(tableResult.Value.Rows.Count);
            }
            return tableResult;
        }
結束語

由於時間的關系(最近工作崗位變動),最重要,也是這套框架元老級組件——數據庫部分,介紹的並不詳細。接下來,可能對 Sofire.Data 的高級部分進行講解,比如對查詢前后的事件支持,查詢結果自動轉換為對象/集合。不過這種比較代碼性的東西,的確比較難閱讀,也讓我異常糾結。

額,好像很多人想覺得我這款博客皮膚不錯?其實這一款博客皮膚是參考 李寶亨達人 的博客風格進行改版的,很感謝他的皮膚(他是綠色版,我是藍色版)。

我很懶,但如果您在使用這套組件中遇見任何問題或者有任何建議意見,可以在博客留言,我將會及時回復。源碼已更新。稍后上傳。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM