【自然框架】之数据访问 —— 再小的类库也需要设计。

 

  以前也写过几篇关于数据访问的,这里是最新的总结。麻雀虽小五脏俱全,数据访问也许不起眼,但是也要好好的设计一翻。从2004年开始用自己的数据访问,一直到现在,经历过两次大的改版,随着需求的变化,也增加了不少的功能,小修小改那就更多了。目的就是能够让自己更轻松一点。整理思路、整理代码,写点东西,一个是给自己留个脚印;另外一个,说不定也许能够给大家帮个小忙。

 

目标:

  简单、好用、易扩展、稳定、性能。

 

特点:

1、 基于ADO.net 2.0 编写,理论上可以支持多种数据库,目前测试了SQL Server 和Access,一位朋友帮忙测试了MySQL。Orcale等其他数据库没有测试过。
2、 使用非常简单。
3、 支持事务、存储过程、参数化SQL等。
4、 对存储过程的参数进行封装,更便于操作和更换数据库。
5、 如果运行是出现异常,可以把异常信息、出错的SQL保存到文本文件里面,便于调试、修改错误。
6、 可以方便的扩展相关功能,遵循关闭开放原则。

不承担的责任:
1、 不对SQL语句进行检查。
2、 不负责防止SQL注入。
3、 不负责分页。

 

图示:

 

 

结构:

1、 两个工厂
  CommonFactory:生成Db系列的实例,比如DbConnection、DbCommand等。内部使用。他们都是抽象基类不能直接new,需要相应的子类的实例,比如new SqlConnection、new SqlCommand等。这个就需要根据当前的需求(驱动类型)来确定了,也就是这个工厂的职责。
DALFactory:调用者使用的工厂,通过这个工厂,根据数据驱动类型,生成数据访问的实例。

 

2、 主体部分
  DataAccessLibrary:这个是数据访问的核心部分,相当于大树的主干。定义了一个DbCommand Command,通过他来实现各种功能。
主体部分仅实现最基本的功能,定义内部结构、成员,实现输入和输出的功能。
输入主要是ExecuteNonQuery。通过他来传递添加、修改、删除的SQL语句(包括参数化SQL和存储过程)。还有一个 ExecuteExists,用来判断数据库里是否存在指定的记录。

  输出部分主要是ExecuteReader,这个大家都不陌生吧。其他的原则上都是通过扩展(配件)的方式来实现,不过为了便于调用,还是增加了ExecuteString、T ExecuteScalar<T>(string text)两个函数。这个对于我来说比较常用,所以就放在主体部分里面了。
另外可以通过子类来实现支持不同数据库的差异的部分。

 

3、 配件部分
  这个就比较多了,比如对事务的处理、对存储过程的参数的封装、对Json 的处理、对添加、修改用SQL(包括参数化SQL)的处理等。每一个都是一个“配件”,这样就可以通过增加配件的方式增加需要的功能。比如以前是不支持Json格式的记录的,但是想玩玩ajax,选择json来传递数据,那么就需要把提取出来的数据转换Json格式。那么就可以增加一个“配件”,就是增加一个类,而不影响其他代码。
  增加功能,并不影响其他的代码,这个就是对扩展开放,对修改关闭。

 

实例

 

//发回复  

Reply.bodyUBB = Request.Form["Editor"];  

Reply.topicID = int.Parse(this.DataID);  

#region 验证信息  

if (Reply.bodyUBB.Length < 10)  

{  

    Functions.PageRegisterAlert(Page, "请填写内容,或者内容太短!至少也得写10个字,对吧。");  

    return;  

}  

#endregion  

#region 内部字段  

int userID = int.Parse(UserInfo.UserID);  

string ip = Request.UserHostAddress;  

DateTime dateTime = DateTime.Now;  

string bodyHTML;  

#endregion  

#region 处理UBB  

bodyHTML = bodyUBB.Replace("\r", "<BR>");  

//其他略  

#endregion  

//开启事务  

Dal.ManagerTran.TranBegin();  

ManagerParameter parm = Dal.ManagerParameter;  

#region 设置参数  

parm.ClearParameter();  

parm.AddNewInParameter("TopicID", Reply.topicID);        //   

parm.AddNewInParameter("回复内容", bodyUBB);  

parm.AddNewInParameter("内容HTML", bodyHTML);  

parm.AddNewInParameter("回复人ID", userID);  

parm.AddNewInParameter("回复人IP", ip, 15);  

parm.AddNewInParameter("回复时间", dateTime);  

#endregion  

              

#region 保存回复,表名:BBS_Reply  

Dal.ModifyData.InsertData("BBS_Reply");  

if (Dal.ErrorMessage.Length > 0)  

{  

    //出现异常  

    Functions.PageRegisterAlert(Page, "保存您发的回复的时候出现意外情况!");  

    return;  

}  

#endregion  

string sql;  

#region 更新回复人的回复数量,回复时间,以及各种积分。  

sql = @"update BBS_Topic set 回复次数 = 回复次数 + 1 ,最后回复时间 = GetDate(),  

最后回复人ID = {0},   where TopicID ={1}";  

Dal.ExecuteNonQuery(string.Format(sql, userID,topicID));  

if (Dal.ErrorMessage.Length > 0)  

{  

    //出现异常  

    Functions.PageRegisterAlert(Page, "更新回复数量的时候出现意外情况!");  

    return;  

}  

#endregion  

#region 更新回复人的参与讨论的帖子  

sql = "select top 1 UserInTopicID from BBS_UserInTopic where UserID ={0} and TopicID={1} ";  

string userInTopicID = Dal.ExecuteString(string.Format(sql, userID, topicID));  

sql = "select top 1 回复次数 from BBS_Topic where TopicID={0} ";  

string reCount = Dal.ExecuteString(string.Format(sql, topicID)) ?? "0";  

int intReCount = int.Parse(reCount);  

if (userInTopicID == null)  

{  

    #region 没有参与过,添加记录  

    parm.ClearParameter();  

    parm.AddNewInParameter("UserID", userID);  

    parm.AddNewInParameter("TopicID", topicID);  

    parm.AddNewInParameter("最后查看时间", dateTime);  

    parm.AddNewInParameter("最后查看回复数", intReCount);  

    Dal.ModifyData.InsertData("BBS_UserInTopic");  

    if (Dal.ErrorMessage.Length > 0)  

    {  

        //出现异常  

        Functions.PageRegisterAlert(Page, "增加您参与讨论的帖子的时候出现意外情况!");  

        return;  

    }  

    #endregion  

}  

else 

{  

    #region 参与过,修改记录  

    parm.ClearParameter();  

    parm.AddNewInParameter("最后查看时间", dateTime);  

    parm.AddNewInParameter("最后查看回复数", intReCount);  

    Dal.ModifyData.UpdateData("BBS_UserInTopic", "UserInTopicID=" + userInTopicID);  

    if (Dal.ErrorMessage.Length > 0)  

    {  

        //出现异常  

        Functions.PageRegisterAlert(Page, "更新参与讨论的帖子的时候出现意外情况!");  

        return;  

    }  

    #endregion  

}  

#endregion  

//提交事务  

Dal.ManagerTran.TranCommit();  

//正常  

lblMsg.Text = "发表回复成功!感谢您的参与!1秒后重新加载帖子。";  

Functions.PageRegisterJavascript(Page, "reload()"); 

 

简单写一个,以论坛的回复为例,这个大家都熟悉,不是太简单也不是很复杂。

  这个没有按照三层的方式来写,因为我分不出来哪些是业务逻辑,哪些是数据访问,都写到一起了,呵呵。但是这并不是说数据访问只能写成这个样子。这个只是一个具体的、综合性的例子。也可以把他分一分,找到业务逻辑的部分,提取出去,放在业务层;把数据访问的部分也提出出去,放在数据层。
这里仅仅是一个数据访问的调用的示例,并不是说要不要分层。

时间: 2024-09-20 10:41:32

【自然框架】之数据访问 —— 再小的类库也需要设计。的相关文章

【自然框架】数据访问之精雕细琢(一)存储过程的参数

  目标: 对存储过程的参数进行封装,达到方便操作.更换数据库不需要改代码的目的. 特点:1. 调用方便2. 没有数据库特征. 正文: 现在参数化SQL语句越来越常用了,这就涉及到如何写存储过程的参数的问题.您也许会问,这有啥的直接写不就可以了么?就像下面这段代码.   string sql = "insert into OS_User_Info values(@UserID,@PersonID,@NikeName,@ProvinceID,@CityID,@CountyID,@Introduct

Spring Data JPA v1.0.0.M1发布 Spring框架应用数据访问工具

Spring Data 项目的目的是为了简化构建基于 Spring 框架应用的数据访问计数,包括http://www.aliyun.com/zixun/aggregation/33495.html">非关系数据库.Map-Reduce 框架.云数据服务等等:另外也包含对关系数据库的访问支持. Spring Data JPA project 刚刚发布了第二个里程碑版本,新的官方公布详情如下: I'd like to announce the release of the first mile

【自然框架】注册会员活动——第一份代码的修改建议(第一版)

  前情回顾:       自然框架开源社区的第一次活动--实现会员注册 (活动介绍)     自然框架开源社区第一次活动的资源包  (内含数据库设计.数据库文档.实例代码)     参与方式   (可以在这里报名参加)     人员表设计思想 -- 也许会有点帮助 (数据库的设计思路)     [自然框架]开源社区活动,会员注册的第一份代码!  (第一份代码的 原版代码)       下载"好坏"的会员注册完整代码.("好坏"提供的原始版代码)     下载我的修

.NET 数据访问架构指南(一)

访问|架构|数据 概述:本文提供了在多层.NET应用程序中实施基于ADO.NET的数据访问层的指导原则.其重点是一组通用数据访问任务和方案,并指导你选择最合适的途径和技术(68张打印页). 目录 ADO.NET简介 管理数据库链接 错误处理 性能 通过防火墙建立链接 处理 BLOBs 事务处理 数据分页 简介 如果你在为.NET应用程序设计数据访问层,那么就应该把 Microsoft ADO.NET用作数据访问模型.ADO.NET扩展丰富,并且支持结合松散的数据访问需求.多层Web应用程序及We

微软的数据访问技术小结

访问|数据|微软 微软的数据访问技术大体有以下几类:一.UDA(UniversalDataAccess)这是微软提供的通用数据访问策略.包括ADO.OLEDB和ODBC.它不光提供了数据库的访问能力,对于其它的数据存储技术也同样支持,如目录服务.Excel的表格数据和Exchange服务器数据等. 二.ODBC(OpenDatabaseConnectivity)这是目前公认的最好的数据访问技术.ODBC结构包含了一个普通的基于SQL的API,它利用对应的驱动程序来开发特定的数据库程序.该技术市场

.net中的数据访问框架比较

Windows平台上数据访问技术飞速发展,在现在的项目中该如何选择合适的技术且该技术能有比较长的持续周期呢? 通过查询和汇总了网上的一些资料,希望能够为我们在开发中架构选型提供帮助. 发展方向 微软官方的一个说明. http://www.infoq.com/cn/news/2010/07/Top-10-Questions-on-Data http://msdn.microsoft.com/en-us/data/bb525059.aspx 微软宣称"会继续开发这些技术",但不会继续使用&

Java的Spring框架中DAO数据访问对象的使用示例_java

Spring DAO之JDBC  Spring提供的DAO(数据访问对象)支持主要的目的是便于以标准的方式使用不同的数据访问技术, 如JDBC,Hibernate或者JDO等.它不仅可以让你方便地在这些持久化技术间切换, 而且让你在编码的时候不用考虑处理各种技术中特定的异常. 为了便于以一种一致的方式使用各种数据访问技术,如JDBC.JDO和Hibernate, Spring提供了一套抽象DAO类供你扩展.这些抽象类提供了一些方法,通过它们你可以 获得与你当前使用的数据访问技术相关的数据源和其他

Java的MyBatis+Spring框架中使用数据访问对象DAO模式的方法_java

SqlSessionTemplateSqlSessionTemplate是MyBatis-Spring的核心.这个类负责管理MyBatis的SqlSession,调用MyBatis的SQL方法,翻译异常.SqlSessionTemplate是线程安全的,可以被多个DAO所共享使用. 当调用SQL方法时,包含从映射器getMapper()方法返回的方法,SqlSessionTemplate将会保证使用的SqlSession是和当前Spring的事务相关的.此外,它管理session的生命周期,包含

DataRabbit 轻量的数据访问框架(03) -- IOrmAccesser(续)

   本文将接着 DataRabbit 轻量的数据访问框架 -- IOrmAccesser 继续介绍IOrmAccesser的一些高级功能.这些高级功能需要DataRabbit.ORM.ISmartEntity接口的支持.注意,对于Entity class 来说,该接口并不是强制的. (1)关于含自增字段的Entity插入:      插入后,Entity中对应自增字段的属性将被正确地赋为数据库中自增结果值.    如果Entity class 继承了ISmartEntity接口,那么这个Ent