Sofire v1.0 开源——快速数据库访问模式 Sofire.Data(2)
那么,Sofire.v1.0包含什么内容?
下载地址:Sofire.v1.0-1206041、数据库访问(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.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 的高级部分进行讲解,比如对查询前后的事件支持,查询结果自动转换为对象/集合。不过这种比较代码性的东西,的确比较难阅读,也让我异常纠结。
额,好像很多人想觉得我这款博客皮肤不错?其实这一款博客皮肤是参考 李宝亨达人 的博客风格进行改版的,很感谢他的皮肤(他是绿色版,我是蓝色版)。
我很懒,但如果您在使用这套组件中遇见任何问题或者有任何建议意见,可以在博客留言,我将会及时回复。源码已更新。稍后上传。