说明:此篇文章是给那些和我一样仍在使用ADO.NET访问数据库的.NET开发人员写的,因为某些原因,比如还在使用.NET3.0以下版本开发.NET应用或者所使用的数据库对ORM支持不是很好,或者是对ORM的性能有所怀疑(其实在访问量不是很大的情况下没有必要过分追求性能的极限)等等,这部分人仍在使用传统的ADO.NET来访问数据库,他们或手写或采用代码生成工具来生成实体类和增删改查的SQL语句,在将DataTable或者DataReader转换成对应的实体类的时候仍需要一行行写代码,本类就是为了解决这个问题的,可以用几个类来实现方便快捷的转换。本类库在SQL Server/MySQL/SQLite下测试通过,由于条件有限未在所有的数据库下测试,如果有问题请在此留言或者在周公的微博留言(http://weibo.com/zhoufoxcn)。

其实在写这套类库之前,去年周公就写了两篇有关的文章,一篇叫《用C#打造自己的实体转换器》,另一篇叫《利用ADO.NET的体系架构打造通用的数据库访问通用类》(两篇文章的阅读地址会在文末给出),本篇的代码就是在这两篇文章的基础上经过实际应用修改而成,主要是修正了几个问题:1.如果在SELECT子句的字段中不包含对应实体类的某个属性,那么该属性的值就为它对应Type的默认值(如int,short为0,引用类型为null),而不是像以前那样用Ignorable,因为有些属性可能在某个查询中需要而在另外一个查询中不需要,采用Ignorable这样的Attribute的话太武断;2.修正了在泛型类型时的错误;3.在类的属性类型中除了支持常见数据类型(数值类型、可空类型和string)之外,还支持byte[]这种常见的数据类型。
本类库共有5个类:DbProviderType、ProviderFactory、DbUtility、EntityReader、ColumnNameAttribute。
其中DbProviderType、ProviderFactory、DbUtility三个类的相关代码如下:
 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Data; 
  4. using System.Data.Common; 
  5.  
  6. namespace NetSkycn.Data 
  7.     /// <summary> 
  8.     /// 通用数据库访问类,封装了对数据库的常见操作 
  9.     /// 作者:周公 
  10.     /// 创建日期:2011-07-18 
  11.     /// 修改日期:2012-04-12 
  12.     /// 新浪微博地址:http://weibo.com/zhoufoxcn 
  13.     /// </summary> 
  14.     public sealed class DbUtility 
  15.     { 
  16.         public string ConnectionString { getset; } 
  17.         private DbProviderFactory providerFactory; 
  18.         /// <summary> 
  19.         /// 构造函数 
  20.         /// </summary> 
  21.         /// <param name="connectionString">数据库连接字符串</param> 
  22.         /// <param name="providerType">数据库类型枚举,参见<paramref name="providerType"/></param> 
  23.         public DbUtility(string connectionString, DbProviderType providerType) 
  24.         { 
  25.             ConnectionString = connectionString; 
  26.             providerFactory = ProviderFactory.GetDbProviderFactory(providerType); 
  27.             if (providerFactory == null
  28.             { 
  29.                 throw new ArgumentException("Can't load DbProviderFactory for given value of providerType"); 
  30.             } 
  31.         } 
  32.         /// <summary>    
  33.         /// 对数据库执行增删改操作,返回受影响的行数。    
  34.         /// </summary>    
  35.         /// <param name="sql">要执行的增删改的SQL语句</param>    
  36.         /// <param name="parameters">执行增删改语句所需要的参数</param> 
  37.         /// <returns></returns>   
  38.         public int ExecuteNonQuery(string sql, IList<DbParameter> parameters) 
  39.         { 
  40.             return ExecuteNonQuery(sql, parameters, CommandType.Text); 
  41.         } 
  42.         /// <summary>    
  43.         /// 对数据库执行增删改操作,返回受影响的行数。    
  44.         /// </summary>    
  45.         /// <param name="sql">要执行的增删改的SQL语句</param>    
  46.         /// <param name="parameters">执行增删改语句所需要的参数</param> 
  47.         /// <param name="commandType">执行的SQL语句的类型</param> 
  48.         /// <returns></returns> 
  49.         public int ExecuteNonQuery(string sql, IList<DbParameter> parameters, CommandType commandType) 
  50.         { 
  51.             using (DbCommand command = CreateDbCommand(sql, parameters, commandType)) 
  52.             { 
  53.                 command.Connection.Open(); 
  54.                 int affectedRows = command.ExecuteNonQuery(); 
  55.                 command.Connection.Close(); 
  56.                 return affectedRows; 
  57.             } 
  58.         } 
  59.  
  60.         /// <summary>    
  61.         /// 执行一个查询语句,返回一个关联的DataReader实例    
  62.         /// </summary>    
  63.         /// <param name="sql">要执行的查询语句</param>    
  64.         /// <param name="parameters">执行SQL查询语句所需要的参数</param> 
  65.         /// <returns></returns>  
  66.         public DbDataReader ExecuteReader(string sql, IList<DbParameter> parameters) 
  67.         { 
  68.             return ExecuteReader(sql, parameters, CommandType.Text); 
  69.         } 
  70.  
  71.         /// <summary>    
  72.         /// 执行一个查询语句,返回一个关联的DataReader实例    
  73.         /// </summary>    
  74.         /// <param name="sql">要执行的查询语句</param>    
  75.         /// <param name="parameters">执行SQL查询语句所需要的参数</param> 
  76.         /// <param name="commandType">执行的SQL语句的类型</param> 
  77.         /// <returns></returns>  
  78.         public DbDataReader ExecuteReader(string sql, IList<DbParameter> parameters, CommandType commandType) 
  79.         { 
  80.             DbCommand command = CreateDbCommand(sql, parameters, commandType); 
  81.             command.Connection.Open(); 
  82.             return command.ExecuteReader(CommandBehavior.CloseConnection); 
  83.         } 
  84.  
  85.         /// <summary>    
  86.         /// 执行一个查询语句,返回一个包含查询结果的DataTable    
  87.         /// </summary>    
  88.         /// <param name="sql">要执行的查询语句</param>    
  89.         /// <param name="parameters">执行SQL查询语句所需要的参数</param> 
  90.         /// <returns></returns> 
  91.         public DataTable ExecuteDataTable(string sql, IList<DbParameter> parameters) 
  92.         { 
  93.             return ExecuteDataTable(sql, parameters, CommandType.Text); 
  94.         } 
  95.         /// <summary>    
  96.         /// 执行一个查询语句,返回一个包含查询结果的DataTable    
  97.         /// </summary>    
  98.         /// <param name="sql">要执行的查询语句</param>    
  99.         /// <param name="parameters">执行SQL查询语句所需要的参数</param> 
  100.         /// <param name="commandType">执行的SQL语句的类型</param> 
  101.         /// <returns></returns> 
  102.         public DataTable ExecuteDataTable(string sql, IList<DbParameter> parameters, CommandType commandType) 
  103.         { 
  104.             using (DbCommand command = CreateDbCommand(sql, parameters, commandType)) 
  105.             { 
  106.                 using (DbDataAdapter adapter = providerFactory.CreateDataAdapter()) 
  107.                 { 
  108.                     adapter.SelectCommand = command; 
  109.                     DataTable data = new DataTable(); 
  110.                     adapter.Fill(data); 
  111.                     return data; 
  112.                 } 
  113.             } 
  114.         } 
  115.  
  116.         /// <summary>    
  117.         /// 执行一个查询语句,返回查询结果的第一行第一列    
  118.         /// </summary>    
  119.         /// <param name="sql">要执行的查询语句</param>    
  120.         /// <param name="parameters">执行SQL查询语句所需要的参数</param>    
  121.         /// <returns></returns>    
  122.         public Object ExecuteScalar(string sql, IList<DbParameter> parameters) 
  123.         { 
  124.             return ExecuteScalar(sql, parameters, CommandType.Text); 
  125.         } 
  126.  
  127.         /// <summary>    
  128.         /// 执行一个查询语句,返回查询结果的第一行第一列    
  129.         /// </summary>    
  130.         /// <param name="sql">要执行的查询语句</param>    
  131.         /// <param name="parameters">执行SQL查询语句所需要的参数</param>    
  132.         /// <param name="commandType">执行的SQL语句的类型</param> 
  133.         /// <returns></returns>    
  134.         public Object ExecuteScalar(string sql, IList<DbParameter> parameters, CommandType commandType) 
  135.         { 
  136.             using (DbCommand command = CreateDbCommand(sql, parameters, commandType)) 
  137.             { 
  138.                 command.Connection.Open(); 
  139.                 object result = command.ExecuteScalar(); 
  140.                 command.Connection.Close(); 
  141.                 return result; 
  142.             } 
  143.         } 
  144.  
  145.         /// <summary> 
  146.         /// 查询多个实体集合 
  147.         /// </summary> 
  148.         /// <typeparam name="T">返回的实体集合类型</typeparam> 
  149.         /// <param name="sql">要执行的查询语句</param>    
  150.         /// <param name="parameters">执行SQL查询语句所需要的参数</param> 
  151.         /// <returns></returns> 
  152.         public List<T> QueryForList<T>(string sql, IList<DbParameter> parameters) where T : new() 
  153.         { 
  154.             return QueryForList<T>(sql, parameters, CommandType.Text); 
  155.         } 
  156.  
  157.         /// <summary> 
  158.         ///  查询多个实体集合 
  159.         /// </summary> 
  160.         /// <typeparam name="T">返回的实体集合类型</typeparam> 
  161.         /// <param name="sql">要执行的查询语句</param>    
  162.         /// <param name="parameters">执行SQL查询语句所需要的参数</param>    
  163.         /// <param name="commandType">执行的SQL语句的类型</param> 
  164.         /// <returns></returns> 
  165.         public List<T> QueryForList<T>(string sql, IList<DbParameter> parameters, CommandType commandType) where T : new() 
  166.         { 
  167.             DataTable data = ExecuteDataTable(sql, parameters, commandType); 
  168.             return EntityReader.GetEntities<T>(data); 
  169.         } 
  170.         /// <summary> 
  171.         /// 查询单个实体 
  172.         /// </summary> 
  173.         /// <typeparam name="T">返回的实体集合类型</typeparam> 
  174.         /// <param name="sql">要执行的查询语句</param>    
  175.         /// <param name="parameters">执行SQL查询语句所需要的参数</param> 
  176.         /// <returns></returns> 
  177.         public T QueryForObject<T>(string sql, IList<DbParameter> parameters) where T : new() 
  178.         { 
  179.             return QueryForObject<T>(sql, parameters, CommandType.Text); 
  180.         } 
  181.  
  182.         /// <summary> 
  183.         /// 查询单个实体 
  184.         /// </summary> 
  185.         /// <typeparam name="T">返回的实体集合类型</typeparam> 
  186.         /// <param name="sql">要执行的查询语句</param>    
  187.         /// <param name="parameters">执行SQL查询语句所需要的参数</param>    
  188.         /// <param name="commandType">执行的SQL语句的类型</param> 
  189.         /// <returns></returns> 
  190.         public T QueryForObject<T>(string sql, IList<DbParameter> parameters, CommandType commandType) where T : new() 
  191.         { 
  192.             return QueryForList<T>(sql, parameters, commandType)[0]; 
  193.         } 
  194.  
  195.         public DbParameter CreateDbParameter(string name, object value) 
  196.         { 
  197.             return CreateDbParameter(name, ParameterDirection.Input, value); 
  198.         } 
  199.  
  200.         public DbParameter CreateDbParameter(string name, ParameterDirection parameterDirection, object value) 
  201.         { 
  202.             DbParameter parameter = providerFactory.CreateParameter(); 
  203.             parameter.ParameterName = name; 
  204.             parameter.Value = value; 
  205.             parameter.Direction = parameterDirection; 
  206.             return parameter; 
  207.         } 
  208.  
  209.         /// <summary> 
  210.         /// 创建一个DbCommand对象 
  211.         /// </summary> 
  212.         /// <param name="sql">要执行的查询语句</param>    
  213.         /// <param name="parameters">执行SQL查询语句所需要的参数</param> 
  214.         /// <param name="commandType">执行的SQL语句的类型</param> 
  215.         /// <returns></returns> 
  216.         private DbCommand CreateDbCommand(string sql, IList<DbParameter> parameters, CommandType commandType) 
  217.         { 
  218.             DbConnection connection = providerFactory.CreateConnection(); 
  219.             DbCommand command = providerFactory.CreateCommand(); 
  220.             connection.ConnectionString = ConnectionString; 
  221.             command.CommandText = sql; 
  222.             command.CommandType = commandType; 
  223.             command.Connection = connection; 
  224.             if (!(parameters == null || parameters.Count == 0)) 
  225.             { 
  226.                 foreach (DbParameter parameter in parameters) 
  227.                 { 
  228.                     command.Parameters.Add(parameter); 
  229.                 } 
  230.             } 
  231.             return command; 
  232.         } 
  233.     } 
  234.     /// <summary> 
  235.     /// 数据库类型枚举 
  236.     /// </summary> 
  237.     public enum DbProviderType : byte 
  238.     { 
  239.         SqlServer, 
  240.         MySql, 
  241.         SQLite, 
  242.         Oracle, 
  243.         ODBC, 
  244.         OleDb, 
  245.         Firebird, 
  246.         PostgreSql, 
  247.         DB2, 
  248.         Informix, 
  249.         SqlServerCe 
  250.     } 
  251.     /// <summary> 
  252.     /// DbProviderFactory工厂类 
  253.     /// </summary> 
  254.     public class ProviderFactory 
  255.     { 
  256.         private static Dictionary<DbProviderType, string> providerInvariantNames = new Dictionary<DbProviderType, string>(); 
  257.         private static Dictionary<DbProviderType, DbProviderFactory> providerFactoies = new Dictionary<DbProviderType, DbProviderFactory>(20); 
  258.         static ProviderFactory() 
  259.         { 
  260.             //加载已知的数据库访问类的程序集 
  261.             providerInvariantNames.Add(DbProviderType.SqlServer, "System.Data.SqlClient"); 
  262.             providerInvariantNames.Add(DbProviderType.OleDb, "System.Data.OleDb"); 
  263.             providerInvariantNames.Add(DbProviderType.ODBC, "System.Data.ODBC"); 
  264.             providerInvariantNames.Add(DbProviderType.Oracle, "Oracle.DataAccess.Client"); 
  265.             providerInvariantNames.Add(DbProviderType.MySql, "MySql.Data.MySqlClient"); 
  266.             providerInvariantNames.Add(DbProviderType.SQLite, "System.Data.SQLite"); 
  267.             providerInvariantNames.Add(DbProviderType.Firebird, "FirebirdSql.Data.Firebird"); 
  268.             providerInvariantNames.Add(DbProviderType.PostgreSql, "Npgsql"); 
  269.             providerInvariantNames.Add(DbProviderType.DB2, "IBM.Data.DB2.iSeries"); 
  270.             providerInvariantNames.Add(DbProviderType.Informix, "IBM.Data.Informix"); 
  271.             providerInvariantNames.Add(DbProviderType.SqlServerCe, "System.Data.SqlServerCe"); 
  272.         } 
  273.         /// <summary> 
  274.         /// 获取指定数据库类型对应的程序集名称 
  275.         /// </summary> 
  276.         /// <param name="providerType">数据库类型枚举</param> 
  277.         /// <returns></returns> 
  278.         public static string GetProviderInvariantName(DbProviderType providerType) 
  279.         { 
  280.             return providerInvariantNames[providerType]; 
  281.         } 
  282.         /// <summary> 
  283.         /// 获取指定类型的数据库对应的DbProviderFactory 
  284.         /// </summary> 
  285.         /// <param name="providerType">数据库类型枚举</param> 
  286.         /// <returns></returns> 
  287.         public static DbProviderFactory GetDbProviderFactory(DbProviderType providerType) 
  288.         { 
  289.             //如果还没有加载,则加载该DbProviderFactory 
  290.             if (!providerFactoies.ContainsKey(providerType)) 
  291.             { 
  292.                 providerFactoies.Add(providerType, ImportDbProviderFactory(providerType)); 
  293.             } 
  294.             return providerFactoies[providerType]; 
  295.         } 
  296.         /// <summary> 
  297.         /// 加载指定数据库类型的DbProviderFactory 
  298.         /// </summary> 
  299.         /// <param name="providerType">数据库类型枚举</param> 
  300.         /// <returns></returns> 
  301.         private static DbProviderFactory ImportDbProviderFactory(DbProviderType providerType) 
  302.         { 
  303.             string providerName = providerInvariantNames[providerType]; 
  304.             DbProviderFactory factory = null
  305.             try 
  306.             { 
  307.                 //从全局程序集中查找 
  308.                 factory = DbProviderFactories.GetFactory(providerName); 
  309.             } 
  310.             catch (ArgumentException e) 
  311.             { 
  312.                 factory = null
  313.             } 
  314.             return factory; 
  315.         } 
  316.     } 
其中EntityReader、ColumnNameAttribute的代码如下:
没办法,不能在这里粘贴全部代码,所以放在附件下载了,这不是我的错,请大家谅解。
 
本类库经过NUnit测试通过,测试截图如下:

因为测试用的代码涉及到下一篇博文的内容,所以会将测试代码放到下一篇博文中。
2012-04-12
周公

------------------------------------------------

广告:为便于武汉市的.NET开发人员和学生参加在武汉举办的学习交流活动(本人绝没有地域歧视,只为线下交流方便),请有意者加以下QQ群:武汉IT群(11690964),武汉微软移动俱乐部(198027326)。4月14日 本周六 13:30 - 17:00就有一个有关WPhone的免费线下交流活动,地点在武汉光谷软件园DEMO咖啡屋。如果有兴趣请在新浪微博上报名,报名地址:http://event.weibo.com/405882