数据访问层DAL实现过程

开发 后端
DAL为数据访问层Data Access Layer,主要是对原始数据(数据库或者文本文件等存放数据的形式)的操作层,而不是指原始数据,也就是说,是对数据的操作,而不是数据库,具体为业务逻辑层或表示层提供数据服务。我们今天将介绍其实现过程。

  这里为了演示上简单,假设:后台数据库(暂为SqlServer只有用户表User与部门表Department),各表字段相应精简:

User(用户表)
Id 主键
Name 姓名
DeptId 部门编号
其余字段省略......

 

  

Department(部门表)
Id 主键
Name 名称
Desc 部门描述
其余字段省略......

 

  后台数据库:testdb的情况

建立相关的存储过程:

一般我个人也喜欢ORM转换成实体对象(见截图)

(注意:这里增加了DeptTitle属性<部门名称>)

  现在就是访问数据库SqlServer类型,封装到SqlserverProvider中。如果将来访问Access数据库,对应访问封装到AccessProvider中。

  (Provider这里表示数据访问提供程序)

  SqlUserProvier专门实现对SqlServer的表User的操作,AccessUserProvider专门实现对Access的表User的操作,很显然,操作功能都相同(增删改查<CRUD>),因而对不同子类的相同部分抽象出来,形成父类(UserProvider)。

开始着手具体子类实现:SqlUserProvider:UserProvider

  (上图数据库连接串错误:单词integrated才是正确的,***面调试错误后改正。)

  我们发现重载的GetUsers方法,大量代码重复,进行方法重构(重复代码重构为方法GetUsersFromReader)!

  继续具体实现父类的抽象方法:GetUserById,发现该方法的部分代码与先前的GetUsersFromReader方法中的部分代码又重复了!

  发现上图红色部分重复(该图GetUserById方法忘记传递存储过程所需的参数了),再接着方法重构,提炼重复的代码,避免以后改动的多次修改。

  接着编写该类后续的方法(增/删/改):(可以打开VS开发环境中的<服务器资源管理器>,连接上对应的数据库后,看存储过程的参数,以免编码遗忘传参)

接着也来看看 类:AccessUserProvider,见下图

  上图GetUsers方法中的查询语句没有联合查询,后续会改动。(这里仅仅示范,其似Access是可以类似建立查询表<后台调用类似存储过程方式>)

  我们发现UserProvider的两个子类的方法GetUserFromReader和GetUsersFromReader有重复代码(仅仅是方法的参数不同) [想办法抽象出来,放在父类中]

  而方法的参数虽然是SqlDataReader与OleDbDataReader,但是查看定义,看到它们有自己的父类:DbDataReader。

  public class SqlDataReader : DbDataReader, IDataReader, IDisposable, IDataRecord

  public sealed class OleDbDataReader : DbDataReader

  改写父类:UserProvider

父类的方法加上修饰符protected,是为了确保只有子类能够访问。

  子类便可以直接调用父类的方法了(GetUserFromReader和GetUsersFromReader方法),见截图:

类似的完善SqlDepartmentProvider类和AccessDepartmentProvider类的代码

  (父类:DepartmentProvider提供保护方法GetDeparmentFromReader和GetDepartmentsFromReader)

  每个具体的子类Provider都重复了属性:ConnString,所以决定建一个父类:DataAccess来存放该属性(UserProvider与DepartProvider都继承自它),实际上DataAccess还可以包含其它的属性和共用方法。

  1. namespace抽象工厂模式.DAL  
  2. {  
  3. publicabstractclassDataAccess  
  4. {  
  5. privatestring_connString ="";  
  6. publicstringConnString  
  7. get{ return_connString; } }  
  8. }  

   public abstract class UserProvider:DataAccess

  public abstract class DepartmentProvider:DataAccess

  通常:数据库连接串的内容都是存储在对应的配置文件中,而不硬编码。

  桌面应用程序—[app.config],web应用程序---[web.config],这里以app.config示例,数据库连接串先按照SqlServer数据库访问的。

 

  1. <?xml version="1.0" encoding="utf-8" ?> 
  2. <configuration> 
  3. <connectionStrings> 
  4. <add name="DBConnString" 
  5. connectionString="SERVER=.sqlexpress;DATABASE=testdb;INTEGRATED SECURITY=true"/> 
  6. </connectionStrings> 
  7. </configuration> 

  一定要手动引用:System.configuration,然后通过ConfigurationManager类来访问连接串。

  可以想象,根据数据库的类型不同,实际底层操控的数据提供程序为Sql__Provider或是Access__Provider。

  但对于用户调用者(业务逻辑层)只需要操控Provider就可以了。

  假设我所在城市有两个行政分区(东一区和西二区),有一家“真不错”总店[经营快餐系列的]在这两个区都有连锁店,对外统一电话:1111777。

  (设一个总机号码当然方便了,总不至于将来开了10家分店,对外公布10个电话号码,谁能记住啊?)

  比如说:我现在饿了,想吃这家提供的“经济型快餐(一素<炒莴苣>一汤<豆腐汤>)”,我只要打电话111177,那边只需要了解我的地址就可以了。(可以想象:知道了我的地址<就能明白所在行政区,然后公司总店去指派所在区的分店来服务>),对于客户我而言:如何指派哪家分店来服务,以及经济型快餐如何制作的,我都不会关心的。我只关心:要好吃,然后要快点(毕竟,饿太久会受不了的。)

  回到我们的程序:

  UserProvider好比一个物品蔬菜<莴苣>,DepartmentProvider好比汤菜<豆腐>。Access文件夹[经济型],SqlServer文件夹[商务型] (你会问一个题外问题:有荤菜吗?我的回答是:尽量别吃,如今都是激素喂出来的<现在人们消耗太快了,以前自然方式半年才能长大的动物,如今1个月人工方式就用激素喂成了>。吃多了,身体容易得病)。

  只有一个问题:既然BLL(相对于DAL就是客户调用者)只认(UserProvider/DepartmentProvider),又是如何调用实际其作用的子类呢?

  这就需要用到设计模式中的<简单工厂模式> (具体选择哪个子类实际上用父类来完成<根据客户配置需求>)

当然这里的配置文件:数据库连接串和providerType需要匹配好。

  父类:UserProvider我们提供静态的Instance,来决定实际的子类(SqlUserProvider或者AccessUserProvider,根据配置文件的ProviderType的value来定)

  如果将来出现了OracleUserProvider/DB2UserProvider/MySqlUserProvider/XmlUserProvider,这个蓝色框框仍然需要增加case分支。这就不好了,需要再编码(修改),好的设计方式应该是对扩展开放,对修改封闭。而且这里罗列出了所有的具体子类Provider,其实只需要一个子类Provider,但是其他的子类Provider也被迫出现在一起<大杂烩>(其实子类之间出现了耦合) 所以这种方式不可取,需要解决。

  这里用反射的方式来解决这个问题。

  首先约束:ProviderType的赋值需要规范,只能从(Sql/Access/DB2/MySql/Xml)选择一个呢。可以发现:实际的子类名:ProviderType的值+“UserProvider”。

 

  1. staticpublicUserProvider Instance  
  2. {  
  3. get 
  4. {  
  5. if(_instance == null)  
  6. {  
  7. stringproviderTypeName=ConfigurationManager.AppSettings["ProviderType"]  
  8. +"UserProvider";  
  9. _instance =  
  10. Activator.CreateInstance(Type.GetType(providerTypeName)) asUserProvider;  
  11. }  
  12. return_instance;  
  13. }  

 

  如果:你的DAL是单独用程序集方式建立的项目(类库),请使用Assembly.Load等方式,这里由于是以文件夹方式组织的(DAL文件夹)<用Activator.CreateInstance可以OK.>

  以后客户端(BLL)调用的时候:比如删除用户表的记录,就可以如下调用了:

  UserProvider.Instance.DeleteUser(id)了。//这里BLL已经不知道是由哪个子类(如SqlUserProvider)来实际工作的。

  进行一下测试,看是否运行正常!

  发现错误:一:数据库连接串需要修改:

二:文件夹SqlServer改成Sql。以前的命名空间对应改动下:

  namespace抽象工厂模式.DAL.Provider.Sql

  {

  publicclassSqlDepartmentProvider:DepartmentProvider

  ………………………………………….

  namespace抽象工厂模式.DAL.Provider.Sql

  {

  publicclassSqlUserProvider:UserProvider

  ………………………………………………………….

  三:Type.GetType(需要完整的限定名)

测试通过:但发现没有DeptTitle数据,查找错误发现

 

  1.   publicUser(intid, stringname, intdeptId, stringdeptTitle)  
  2.   {  
  3.   this.Id = id;  
  4.   this.Name = name;  
  5.   this.DeptId = deptId;  
  6.   this.DeptTitle = deptTitle; //DeptTitle;  
  7.   } 

 

附上:AccessUserProvider的代码如下:

 

AccessUserProvider代码

 

  1. usingSystem;  
  2. usingSystem.Collections.Generic;  
  3. usingSystem.Text;  
  4. usingSystem.Data;  
  5. usingSystem.Data.OleDb;  
  6. using抽象工厂模式.DAL;  
  7. using抽象工厂模式.DAL.Entity;  
  8. namespace抽象工厂模式.DAL.Provider.Access  
  9. {  
  10. publicclassAccessUserProvider:UserProvider  
  11. {  
  12. publicoverrideList<User> GetUsers()  
  13. {  
  14. using(OleDbConnection conn = newOleDbConnection(ConnString))  
  15. {  
  16. vardbcmd = conn.CreateCommand();  
  17. dbcmd.CommandText = "GetUsers";  
  18. dbcmd.CommandType = CommandType.StoredProcedure;  
  19. conn.Open();  
  20. returnGetUsersFromReader(dbcmd.ExecuteReader());  
  21. }  
  22. }  
  23. publicoverrideList<User> GetUsers(intdeptId)  
  24. {  
  25. using(OleDbConnection conn = newOleDbConnection(ConnString))  
  26. {  
  27. vardbcmd = conn.CreateCommand();  
  28. dbcmd.CommandText = "GetUsersByDepartmentId";  
  29. dbcmd.CommandType = CommandType.StoredProcedure;  
  30. dbcmd.Parameters.Add("@DeptId", OleDbType.Integer).Value = deptId;  
  31. conn.Open();  
  32. returnGetUsersFromReader(dbcmd.ExecuteReader());  
  33. }  
  34. }  
  35. publicoverrideUser GetUserById(intid)  
  36. {  
  37. using(OleDbConnection conn = newOleDbConnection(ConnString))  
  38. {  
  39. vardbcmd = conn.CreateCommand();  
  40. dbcmd.CommandText = "GetUserById";  
  41. dbcmd.CommandType = CommandType.StoredProcedure;  
  42. dbcmd.Parameters.Add("@Id", OleDbType.Integer).Value =id ;  
  43. conn.Open();  
  44. returnGetUserFromReader(dbcmd.ExecuteReader());  
  45. }  
  46. }  
  47. publicoverrideboolDeleteUser(intid)  
  48. {  
  49. using(OleDbConnection conn = newOleDbConnection(ConnString))  
  50. {  
  51. OleDbCommand cmd = newOleDbCommand(  
  52. "delete from [user] where Id="+ id, conn);  
  53. conn.Open();  
  54. returncmd.ExecuteNonQuery() == 1;  
  55. }  
  56. }  
  57. publicoverrideintInsertUser(User user)  
  58. {  
  59. using(OleDbConnection conn = newOleDbConnection(ConnString))  
  60. {  
  61. OleDbCommand cmd = newOleDbCommand(  
  62. @"insert into [user](name,deptId) values(@id,@name);68select max(id) from [user] as newid",conn);  
  63. cmd.Parameters.Add("@id", OleDbType.Integer).Value = user.Id;  
  64. cmd.Parameters.Add("@name", OleDbType.VarChar).Value = user.Name;  
  65. conn.Open();  
  66. return(int)cmd.ExecuteScalar();  
  67. }  
  68. }  
  69. publicoverrideboolUpdateUser(User user)  
  70. {  
  71. using(OleDbConnection conn = newOleDbConnection(ConnString))  
  72. {  
  73. OleDbCommand cmd = newOleDbCommand(  
  74. "update [user] set name=@name,deptId=@deptid where Id=@id", conn);  
  75. cmd.Parameters.Add("@name", OleDbType.Integer).Value = user.Name;  
  76. cmd.Parameters.Add("@deptid", OleDbType.Integer).Value = user.DeptId;  
  77. cmd.Parameters.Add("@id", OleDbType.Integer).Value = user.Id;  
  78. conn.Open();  
  79. returncmd.ExecuteNonQuery() == 1;  
  80. }  
  81. }  
  82. }  

 

  后台的testdb.mdb截图:

原文链接:http://www.cnblogs.com/netxiaochong/archive/2012/01/10/2318119.html

【编辑推荐】

  1. 系统架构师谈企业应用架构之开卷有益
  2. 系统架构师谈企业应用架构之系统建模1
  3. 系统架构师谈企业应用架构之系统建模2
  4. 系统架构师谈企业应用架构之系统建模3
  5. 系统架构师谈企业应用架构之系统建模4
  6. 系统架构师谈企业应用架构之系统设计规范与原则1
  7. 系统架构师谈企业应用架构之系统设计规范与原则2
  8. 系统架构师谈企业应用架构之业务逻辑层
  9. 系统架构师谈企业应用架构之表现层
  10. 系统架构师谈企业应用架构之服务层
  11. 系统架构师谈企业应用架构之数据访问层
责任编辑:彭凡 来源: 博客园
相关推荐

2011-05-07 12:56:39

数据访问

2009-08-19 10:54:42

ASP.NET数据访问

2011-03-29 09:15:28

通用数据访问层

2009-09-04 18:00:54

C#数据访问层

2012-06-07 10:53:08

架构设计数据访问层设计原则

2010-03-02 11:15:34

PDA访问WCF

2011-05-10 16:44:43

数据访问层

2011-05-05 14:33:34

数据访问层

2009-08-13 14:59:00

C#数据访问层

2012-02-03 09:44:33

.NET

2009-07-24 13:25:43

创建数据访问层

2009-07-24 14:15:51

数据访问层

2009-08-04 10:17:55

ASP.NET SqlASP.NET数据访问

2009-07-24 13:45:28

添加参数化

2009-09-28 13:29:41

加载过程Hibernate访问

2009-07-24 14:23:16

定制编码DAL

2012-08-15 11:03:18

框架项目

2009-07-24 13:25:31

ASP.NET 2.0数据访问层(DAL)

2009-07-24 14:02:39

ASP.NET 2.0

2011-05-17 15:30:27

Oracle数据库ADO
点赞
收藏

51CTO技术栈公众号