`
feiliboos
  • 浏览: 659417 次
文章分类
社区版块
存档分类
最新评论

基于.NET平台的分层架构实战(七-外一篇)——对数据访问层第一种实现(Access+SQL)的重构

 
阅读更多

昨天的文章 基于.NET平台的分层架构实战(七)——数据访问层的第一种实现:Access+SQL 发布后,很多朋友对我的程序提出了意见和建议,在这里先谢谢你们!!!尤其是 金色海洋(jyk),对我的程序提出了很多建设性的意见。
我大体总结了一下,昨天程序的主要缺点有:
1.Connection对象没有关闭
2.DataReader对象没有关闭
3.相似代码太多,造成代码冗余。

其中第一点问题,目前还没有太好的解决方案,主要是因为Connection一旦关闭,DataReader就无法读取了。而且,Connection对象应该会自动在适当的时候关闭(通过观察临时文件得出),并且在实际运行时并无影响(在功能上),所以这里没有专门解决。而针对后面两个问题,我使用了如下解决方案。

对于关闭DataReader的方法,实现起来很简单,在finally里将他关闭就行了。关键是如何去处冗余代码。
经过我的分析,数据访问层的操作可以分为三类:不返回数据,返回单个实体类,返回实体类集合。我将这三种操作的公共部分抽出,写成三个方法放在AccessDALHelper里,类型不同的问题使用泛型解决。
这样做有一个难题,就是不同实体在由DataReader转化为实体类时的代码很不一样,无法抽出。这里,我使用了Strategy模式解决。具体做法是:首先定义一个由DataReader转换为实体类的策略接口,然后为不同的实体编写不同的转换策略,示意图如下:

附件: f5.jpg




可以看出,所有转换策略都要实现IDataReaderToEntityStrategy接口,并且每个策略都有一个自组合,这是以为他们都要实现Singleton模式。而AccessDALHelper与具体策略无关,仅与接口耦合。

下面来看一下具体代码:
首先是IDataReaderToEntityStrategy接口

IDataReaderToEntityStrategy.cs:

IDataReaderToEntityStrategy

  1. 1using System;
  2. 2using System.Collections.Generic;
  3. 3using System.Text;
  4. 4using System.Data;
  5. 5using System.Data.OleDb;
  6. 6
  7. 7namespace NGuestBook.AccessDAL
  8. 8{
  9. 9 /**//// <summary>
  10. 10 /// 由DataReader转换成实体类的策略接口
  11. 11 /// </summary>
  12. 12 public interface IDataReaderToEntityStrategy<T>
  13. 13 {
  14. 14 /**//// <summary>
  15. 15 /// 将DataReader转换为实体类,采用泛型
  16. 16 /// </summary>
  17. 17 /// <param name="dataReader">包含数据的DataReader对象</param>
  18. 18 /// <returns>实体类</returns>
  19. 19 T DataReaderToEntity(OleDbDataReader dataReader);
  20. 20 }
  21. 21}
复制代码

然后以Admin为例,看一下策略的具体实现:
AdminDataReaderToEntityStrategy.cs:

AdminDataReaderToEntityStrategy

  1. 1using System;
  2. 2using System.Collections.Generic;
  3. 3using System.Text;
  4. 4using System.Data;
  5. 5using System.Data.OleDb;
  6. 6using NGuestBook.Entity;
  7. 7
  8. 8namespace NGuestBook.AccessDAL
  9. 9{
  10. 10 /**//// <summary>
  11. 11 /// DataReader到实体类的转换策略-管理员
  12. 12 /// 实现上使用Singleton模式,保证全局唯一实例
  13. 13 /// </summary>
  14. 14 public class AdminDataReaderToEntityStrategy : IDataReaderToEntityStrategy<AdminInfo>
  15. 15 {
  16. 16 private static AdminDataReaderToEntityStrategy singleInstance = null;
  17. 17
  18. 18 /**//// <summary>
  19. 19 /// 私有化构造函数,保证无法外部实例化
  20. 20 /// </summary>
  21. 21 private AdminDataReaderToEntityStrategy() { }
  22. 22
  23. 23 /**//// <summary>
  24. 24 /// 静态方法,用于取得全局唯一实例
  25. 25 /// </summary>
  26. 26 /// <returns>全局唯一实例</returns>
  27. 27 public static AdminDataReaderToEntityStrategy GetInstance()
  28. 28 {
  29. 29 if (singleInstance == null)
  30. 30 {
  31. 31 singleInstance = new AdminDataReaderToEntityStrategy();
  32. 32 }
  33. 33
  34. 34 return singleInstance;
  35. 35 }
  36. 36
  37. 37 /**//// <summary>
  38. 38 /// 由DataReader转换到管理员实体类
  39. 39 /// </summary>
  40. 40 /// <param name="dataReader">包含数据的DataReader对象</param>
  41. 41 /// <returns>管理员实体类</returns>
  42. 42 public AdminInfo DataReaderToEntity(OleDbDataReader dataReader)
  43. 43 {
  44. 44 AdminInfo admin = new AdminInfo();
  45. 45 admin.ID = (int)dataReader["ID"];
  46. 46 admin.Name = (string)dataReader["Name"];
  47. 47 admin.Password = (string)dataReader["Password"];
  48. 48
  49. 49 return admin;
  50. 50 }
  51. 51 }
  52. 52}
复制代码

可以看到,这里实现了一个单件模式。下一个,是重构后的AccessDALHelper,增加了三个方法。
AccessDALHelper.cs:

AccessDALHelper

  1. 1using System;
  2. 2using System.Collections.Generic;
  3. 3using System.Web;
  4. 4using System.Web.Caching;
  5. 5using System.Configuration;
  6. 6using System.Data;
  7. 7using System.Data.OleDb;
  8. 8using NGuestBook.Utility;
  9. 9
  10. 10namespace NGuestBook.AccessDAL
  11. 11{
  12. 12 /**//// <summary>
  13. 13 /// Access数据库操作助手
  14. 14 /// </summary>
  15. 15 public sealed class AccessDALHelper
  16. 16 {
  17. 17 /**//// <summary>
  18. 18 /// 读取Access数据库的连接字符串
  19. 19 /// 首先从缓存里读取,如果不存在则到配置文件中读取,并放入缓存
  20. 20 /// </summary>
  21. 21 /// <returns>Access数据库的连接字符串</returns>
  22. 22 private static string GetConnectionString()
  23. 23 {
  24. 24 if (CacheAccess.GetFromCache("AccessConnectionString") != null)
  25. 25 {
  26. 26 return CacheAccess.GetFromCache("AccessConnectionString").ToString();
  27. 27 }
  28. 28 else
  29. 29 {
  30. 30 string dbPath = ConfigurationManager.AppSettings["AccessPath"];
  31. 31 string dbAbsolutePath = HttpContext.Current.Server.MapPath(dbPath);
  32. 32 string connectionString = ConfigurationManager.AppSettings["AccessConnectionString"];
  33. 33
  34. 34 CacheDependency fileDependency = new CacheDependency(HttpContext.Current.Server.MapPath("Web.Config"));
  35. 35 CacheAccess.SaveToCache("AccessConnectionString", connectionString.Replace("{DBPath}", dbAbsolutePath), fileDependency);
  36. 36
  37. 37 return connectionString.Replace("{DBPath}", dbAbsolutePath);
  38. 38 }
  39. 39 }
  40. 40
  41. 41 /**//// <summary>
  42. 42 /// 执行SQL语句并且不返回任何值
  43. 43 /// </summary>
  44. 44 /// <param name="SQLCommand">所执行的SQL命令</param>
  45. 45 /// <param name="parameters">参数集合</param>
  46. 46 public static void ExecuteSQLNonQuery(string SQLCommand, OleDbParameter[] parameters)
  47. 47 {
  48. 48 OleDbConnection connection = new OleDbConnection(GetConnectionString());
  49. 49 OleDbCommand command = new OleDbCommand(SQLCommand, connection);
  50. 50
  51. 51 for (int i = 0; i < parameters.Length; i++)
  52. 52 {
  53. 53 command.Parameters.Add(parameters);
  54. 54 }
  55. 55
  56. 56 connection.Open();
  57. 57 command.ExecuteNonQuery();
  58. 58 connection.Close();
  59. 59 }
  60. 60
  61. 61 /**//// <summary>
  62. 62 /// 执行SQL语句并返回包含查询结果的DataReader
  63. 63 /// </summary>
  64. 64 /// <param name="SQLCommand">所执行的SQL命令</param>
  65. 65 /// <param name="parameters">参数集合</param>
  66. 66 /// <returns></returns>
  67. 67 public static OleDbDataReader ExecuteSQLDataReader(string SQLCommand, OleDbParameter[] parameters)
  68. 68 {
  69. 69 OleDbConnection connection = new OleDbConnection(GetConnectionString());
  70. 70 OleDbCommand command = new OleDbCommand(SQLCommand, connection);
  71. 71
  72. 72 for (int i = 0; i < parameters.Length; i++)
  73. 73 {
  74. 74 command.Parameters.Add(parameters);
  75. 75 }
  76. 76
  77. 77 connection.Open();
  78. 78 OleDbDataReader dataReader = command.ExecuteReader();
  79. 79 //connection.Close();
  80. 80
  81. 81 return dataReader;
  82. 82 }
  83. 83
  84. 84 /**//// <summary>
  85. 85 /// 执行不需要返回数据的操作
  86. 86 /// </summary>
  87. 87 /// <param name="SQLCommand">SQL命令</param>
  88. 88 /// <param name="parameters">参数</param>
  89. 89 /// <returns>是否成功</returns>
  90. 90 public static bool OperateNonData(string SQLCommand, OleDbParameter[] parameters)
  91. 91 {
  92. 92 try
  93. 93 {
  94. 94 ExecuteSQLNonQuery(SQLCommand, parameters);
  95. 95 return true;
  96. 96 }
  97. 97 catch
  98. 98 {
  99. 99 return false;
  100. 100 }
  101. 101 }
  102. 102
  103. 103 /**//// <summary>
  104. 104 /// 执行返回单个实体类的操作
  105. 105 /// </summary>
  106. 106 /// <typeparam name="T">实体类类型</typeparam>
  107. 107 /// <param name="SQLCommand">SQL命令</param>
  108. 108 /// <param name="parameters">参数</param>
  109. 109 /// <param name="strategy">DataReader到实体类的转换策略</param>
  110. 110 /// <returns>实体类</returns>
  111. 111 public static T OperateEntity<T>(string SQLCommand, OleDbParameter[] parameters, IDataReaderToEntityStrategy<T> strategy)
  112. 112 {
  113. 113 OleDbDataReader dataReader = ExecuteSQLDataReader(SQLCommand, parameters);
  114. 114 try
  115. 115 {
  116. 116 if (!dataReader.HasRows)
  117. 117 {
  118. 118 throw new Exception();
  119. 119 }
  120. 120
  121. 121 dataReader.Read();
  122. 122 return strategy.DataReaderToEntity(dataReader);
  123. 123 }
  124. 124 catch
  125. 125 {
  126. 126 return default(T);
  127. 127 }
  128. 128 finally
  129. 129 {
  130. 130 dataReader.Close();
  131. 131 }
  132. 132 }
  133. 133
  134. 134 /**//// <summary>
  135. 135 /// 执行返回实体类集合的操作
  136. 136 /// </summary>
  137. 137 /// <typeparam name="T">实体类类型</typeparam>
  138. 138 /// <param name="SQLCommand">SQL命令</param>
  139. 139 /// <param name="parameters">参数</param>
  140. 140 /// <param name="strategy">DataReader到实体类的转换策略</param>
  141. 141 /// <returns>实体类</returns>
  142. 142 public static IList<T> OperateEntityCollection<T>(string SQLCommand, OleDbParameter[] parameters, IDataReaderToEntityStrategy<T> strategy)
  143. 143 {
  144. 144 OleDbDataReader dataReader = AccessDALHelper.ExecuteSQLDataReader(SQLCommand, null);
  145. 145 try
  146. 146 {
  147. 147 if (!dataReader.HasRows)
  148. 148 {
  149. 149 throw new Exception();
  150. 150 }
  151. 151
  152. 152 IList<T> entityCollection = new List<T>();
  153. 153 int i = 0;
  154. 154 while (dataReader.Read())
  155. 155 {
  156. 156 entityCollection.Add(strategy.DataReaderToEntity(dataReader));
  157. 157 i++;
  158. 158 }
  159. 159
  160. 160 return entityCollection;
  161. 161 }
  162. 162 catch
  163. 163 {
  164. 164 return default(IList<T>);
  165. 165 }
  166. 166 finally
  167. 167 {
  168. 168 dataReader.Close();
  169. 169 }
  170. 170 }
  171. 171 }
  172. 172}
复制代码

最后以Admin为例,看一下简化后的数据访问层实现:
AdminDAL.cs:

AdminDAL

  1. 1using System;
  2. 2using System.Collections.Generic;
  3. 3using System.Text;
  4. 4using System.Data;
  5. 5using System.Data.OleDb;
  6. 6using NGuestBook.IDAL;
  7. 7using NGuestBook.Entity;
  8. 8
  9. 9namespace NGuestBook.AccessDAL
  10. 10{
  11. 11 public class AdminDAL : IAdminDAL
  12. 12 {
  13. 13 /**//// <summary>
  14. 14 /// 插入管理员
  15. 15 /// </summary>
  16. 16 /// <param name="admin">管理员实体类</param>
  17. 17 /// <returns>是否成功</returns>
  18. 18 public bool Insert(AdminInfo admin)
  19. 19 {
  20. 20 string SQLCommand = "insert into [TAdmin]([Name],[Password]) values(@name,@password)";
  21. 21 OleDbParameter[] parameters ={
  22. 22 new OleDbParameter("name",OleDbType.VarChar,20),
  23. 23 new OleDbParameter("password",OleDbType.VarChar,50)
  24. 24 };
  25. 25 parameters[0].Value = admin.Name;
  26. 26 parameters[1].Value = admin.Password;
  27. 27
  28. 28 return AccessDALHelper.OperateNonData(SQLCommand, parameters);
  29. 29 }
  30. 30
  31. 31 /**//// <summary>
  32. 32 /// 删除管理员
  33. 33 /// </summary>
  34. 34 /// <param name="id">欲删除的管理员的ID</param>
  35. 35 /// <returns>是否成功</returns>
  36. 36 public bool Delete(int id)
  37. 37 {
  38. 38 string SQLCommand = "delete from [TAdmin] where [ID]=@id";
  39. 39 OleDbParameter[] parameters ={
  40. 40 new OleDbParameter("id",OleDbType.Integer)
  41. 41 };
  42. 42 parameters[0].Value = id;
  43. 43
  44. 44 return AccessDALHelper.OperateNonData(SQLCommand, parameters);
  45. 45 }
  46. 46
  47. 47 /**//// <summary>
  48. 48 /// 更新管理员信息
  49. 49 /// </summary>
  50. 50 /// <param name="admin">管理员实体类</param>
  51. 51 /// <returns>是否成功</returns>
  52. 52 public bool Update(AdminInfo admin)
  53. 53 {
  54. 54 string SQLCommand = "update [TAdmin] set [Name]=@name,[Password]=@password where [ID]=@id";
  55. 55 OleDbParameter[] parameters ={
  56. 56 new OleDbParameter("id",OleDbType.Integer),
  57. 57 new OleDbParameter("name",OleDbType.VarChar,20),
  58. 58 new OleDbParameter("password",OleDbType.VarChar,50)
  59. 59 };
  60. 60 parameters[0].Value = admin.ID;
  61. 61 parameters[1].Value = admin.Name;
  62. 62 parameters[2].Value = admin.Password;
  63. 63
  64. 64 return AccessDALHelper.OperateNonData(SQLCommand, parameters);
  65. 65 }
  66. 66
  67. 67 /**//// <summary>
  68. 68 /// 按ID取得管理员信息
  69. 69 /// </summary>
  70. 70 /// <param name="id">管理员ID</param>
  71. 71 /// <returns>管理员实体类</returns>
  72. 72 public AdminInfo GetByID(int id)
  73. 73 {
  74. 74 string SQLCommand = "select * from [TAdmin] where [ID]=@id";
  75. 75 OleDbParameter[] parameters ={
  76. 76 new OleDbParameter("id",OleDbType.Integer)
  77. 77 };
  78. 78 parameters[0].Value = id;
  79. 79
  80. 80 return AccessDALHelper.OperateEntity<AdminInfo>(SQLCommand, parameters, AdminDataReaderToEntityStrategy.GetInstance());
  81. 81 }
  82. 82
  83. 83 /**//// <summary>
  84. 84 /// 按用户名及密码取得管理员信息
  85. 85 /// </summary>
  86. 86 /// <param name="name">用户名</param>
  87. 87 /// <param name="password">密码</param>
  88. 88 /// <returns>管理员实体类,不存在时返回null</returns>
  89. 89 public AdminInfo GetByNameAndPassword(string name, string password)
  90. 90 {
  91. 91 string SQLCommand = "select * from [TAdmin] where [Name]=@name and [Password]=@password";
  92. 92 OleDbParameter[] parameters ={
  93. 93 new OleDbParameter("name",OleDbType.VarChar,20),
  94. 94 new OleDbParameter("password",OleDbType.VarChar,50)
  95. 95 };
  96. 96 parameters[0].Value = name;
  97. 97 parameters[1].Value = password;
  98. 98
  99. 99 return AccessDALHelper.OperateEntity<AdminInfo>(SQLCommand, parameters, AdminDataReaderToEntityStrategy.GetInstance());
  100. 100 }
  101. 101
  102. 102 /**//// <summary>
  103. 103 /// 按管理员名取得管理员信息
  104. 104 /// </summary>
  105. 105 /// <param name="name">管理员名</param>
  106. 106 /// <returns>管理员实体类</returns>
  107. 107 public AdminInfo GetByName(string name)
  108. 108 {
  109. 109 string SQLCommand = "select * from [TAdmin] where [Name]=@name";
  110. 110 OleDbParameter[] parameters ={
  111. 111 new OleDbParameter("name",OleDbType.VarChar,20)
  112. 112 };
  113. 113 parameters[0].Value = name;
  114. 114
  115. 115 return AccessDALHelper.OperateEntity<AdminInfo>(SQLCommand, parameters, AdminDataReaderToEntityStrategy.GetInstance());
  116. 116 }
  117. 117
  118. 118 /**//// <summary>
  119. 119 /// 取得全部管理员信息
  120. 120 /// </summary>
  121. 121 /// <returns>管理员实体类集合</returns>
  122. 122 public IList<AdminInfo> GetAll()
  123. 123 {
  124. 124 string SQLCommand = "select * from [TAdmin]";
  125. 125
  126. 126 return AccessDALHelper.OperateEntityCollection<AdminInfo>(SQLCommand, null, AdminDataReaderToEntityStrategy.GetInstance());
  127. 127 }
  128. 128 }
  129. 129}
复制代码
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics