• 基于.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}
    复制代码
  • 相关阅读:
    C#获取类以及类下的方法(用于Asp.Net MVC)
    ES6学习笔记
    在nuget上发布自己的程序集教程
    C#创建IIS站点及相应的应用程序池,支持IIS6.0+Windows Server 2003. 使用Builder设计模式
    ASP.Net Mvc实现自定义User Identity用户身份识别系统(2)
    ASP.Net Mvc实现自定义User Identity用户身份识别系统(1)
    C#实现.ini文件读写操作
    C#实现注册表 LocalMachine 目录下CURD工具类
    博客园打赏功能(未申请下js权限使用二维码打赏功能)
    WebServeice 动态代理类
  • 原文地址:https://www.cnblogs.com/encounter/p/2188822.html
Copyright © 2020-2023  润新知