代码改变世界

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

2011-03-26 21:31  乱世文章  阅读(166)  评论(0编辑  收藏  举报

昨天的文章 基于.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}
复制代码