zoukankan      html  css  js  c++  java
  • 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 的高级部分进行讲解,比如对查询前后的事件支持,查询结果自动转换为对象/集合。不过这种比较代码性的东西,的确比较难阅读,也让我异常纠结。

    额,好像很多人想觉得我这款博客皮肤不错?其实这一款博客皮肤是参考 李宝亨达人 的博客风格进行改版的,很感谢他的皮肤(他是绿色版,我是蓝色版)。

    我很懒,但如果您在使用这套组件中遇见任何问题或者有任何建议意见,可以在博客留言,我将会及时回复。源码已更新。稍后上传。

  • 相关阅读:
    131. Palindrome Partitioning
    130. Surrounded Regions
    129. Sum Root to Leaf Numbers
    128. Longest Consecutive Sequence
    125. Valid Palindrome
    124. Binary Tree Maximum Path Sum
    122. Best Time to Buy and Sell Stock II
    121. Best Time to Buy and Sell Stock
    120. Triangle
    119. Pascal's Triangle II
  • 原文地址:https://www.cnblogs.com/sofire/p/2513867.html
Copyright © 2011-2022 走看看