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

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

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

  • 相关阅读:
    sysctl.conf文件详解
    linux下高并发网络应用注意事项
    linux 异常
    myeclipse 上安装 Maven3
    windows 系统相关配置
    常用DOS命令总结
    豆瓣爬虫Scrapy“抄袭”改写
    vue基本配置和生命周期
    面试知识点
    ubuntu18.04国内软件源
  • 原文地址:https://www.cnblogs.com/sofire/p/2513867.html
Copyright © 2020-2023  润新知