分享

用C#打造自己的通用数据访问类库(续)

 昵称29801243 2015-12-29

 说明:此篇文章是给那些和我一样仍在使用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.     ///  
  8.     /// 通用数据库访问类,封装了对数据库的常见操作 
  9.     /// 作者:周公 
  10.     /// 创建日期:2011-07-18 
  11.     /// 修改日期:2012-04-12 
  12.     /// 新浪微博地址:http://weibo.com/zhoufoxcn 
  13.     ///  
  14.     public sealed class DbUtility 
  15.     { 
  16.         public string ConnectionString { getset; } 
  17.         private DbProviderFactory providerFactory; 
  18.         ///  
  19.         /// 构造函数 
  20.         ///  
  21.         /// 数据库连接字符串 
  22.         /// 数据库类型枚举,参见 
  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.         ///     
  33.         /// 对数据库执行增删改操作,返回受影响的行数。    
  34.         ///     
  35.         /// 要执行的增删改的SQL语句    
  36.         /// 执行增删改语句所需要的参数 
  37.         ///    
  38.         public int ExecuteNonQuery(string sql, IList parameters) 
  39.         { 
  40.             return ExecuteNonQuery(sql, parameters, CommandType.Text); 
  41.         } 
  42.         ///     
  43.         /// 对数据库执行增删改操作,返回受影响的行数。    
  44.         ///     
  45.         /// 要执行的增删改的SQL语句    
  46.         /// 执行增删改语句所需要的参数 
  47.         /// 执行的SQL语句的类型 
  48.         ///  
  49.         public int ExecuteNonQuery(string sql, IList 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.         ///     
  61.         /// 执行一个查询语句,返回一个关联的DataReader实例    
  62.         ///     
  63.         /// 要执行的查询语句    
  64.         /// 执行SQL查询语句所需要的参数 
  65.         ///   
  66.         public DbDataReader ExecuteReader(string sql, IList parameters) 
  67.         { 
  68.             return ExecuteReader(sql, parameters, CommandType.Text); 
  69.         } 
  70.  
  71.         ///     
  72.         /// 执行一个查询语句,返回一个关联的DataReader实例    
  73.         ///     
  74.         /// 要执行的查询语句    
  75.         /// 执行SQL查询语句所需要的参数 
  76.         /// 执行的SQL语句的类型 
  77.         ///   
  78.         public DbDataReader ExecuteReader(string sql, IList parameters, CommandType commandType) 
  79.         { 
  80.             DbCommand command = CreateDbCommand(sql, parameters, commandType); 
  81.             command.Connection.Open(); 
  82.             return command.ExecuteReader(CommandBehavior.CloseConnection); 
  83.         } 
  84.  
  85.         ///     
  86.         /// 执行一个查询语句,返回一个包含查询结果的DataTable    
  87.         ///     
  88.         /// 要执行的查询语句    
  89.         /// 执行SQL查询语句所需要的参数 
  90.         ///  
  91.         public DataTable ExecuteDataTable(string sql, IList parameters) 
  92.         { 
  93.             return ExecuteDataTable(sql, parameters, CommandType.Text); 
  94.         } 
  95.         ///     
  96.         /// 执行一个查询语句,返回一个包含查询结果的DataTable    
  97.         ///     
  98.         /// 要执行的查询语句    
  99.         /// 执行SQL查询语句所需要的参数 
  100.         /// 执行的SQL语句的类型 
  101.         ///  
  102.         public DataTable ExecuteDataTable(string sql, IList 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.         ///     
  117.         /// 执行一个查询语句,返回查询结果的第一行第一列    
  118.         ///     
  119.         /// 要执行的查询语句    
  120.         /// 执行SQL查询语句所需要的参数    
  121.         ///     
  122.         public Object ExecuteScalar(string sql, IList parameters) 
  123.         { 
  124.             return ExecuteScalar(sql, parameters, CommandType.Text); 
  125.         } 
  126.  
  127.         ///     
  128.         /// 执行一个查询语句,返回查询结果的第一行第一列    
  129.         ///     
  130.         /// 要执行的查询语句    
  131.         /// 执行SQL查询语句所需要的参数    
  132.         /// 执行的SQL语句的类型 
  133.         ///     
  134.         public Object ExecuteScalar(string sql, IList 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.         ///  
  146.         /// 查询多个实体集合 
  147.         ///  
  148.         /// 返回的实体集合类型 
  149.         /// 要执行的查询语句    
  150.         /// 执行SQL查询语句所需要的参数 
  151.         ///  
  152.         public List QueryForList(string sql, IList parameters) where T : new() 
  153.         { 
  154.             return QueryForList(sql, parameters, CommandType.Text); 
  155.         } 
  156.  
  157.         ///  
  158.         ///  查询多个实体集合 
  159.         ///  
  160.         /// 返回的实体集合类型 
  161.         /// 要执行的查询语句    
  162.         /// 执行SQL查询语句所需要的参数    
  163.         /// 执行的SQL语句的类型 
  164.         ///  
  165.         public List QueryForList(string sql, IList parameters, CommandType commandType) where T : new() 
  166.         { 
  167.             DataTable data = ExecuteDataTable(sql, parameters, commandType); 
  168.             return EntityReader.GetEntities(data); 
  169.         } 
  170.         ///  
  171.         /// 查询单个实体 
  172.         ///  
  173.         /// 返回的实体集合类型 
  174.         /// 要执行的查询语句    
  175.         /// 执行SQL查询语句所需要的参数 
  176.         ///  
  177.         public T QueryForObject(string sql, IList parameters) where T : new() 
  178.         { 
  179.             return QueryForObject(sql, parameters, CommandType.Text); 
  180.         } 
  181.  
  182.         ///  
  183.         /// 查询单个实体 
  184.         ///  
  185.         /// 返回的实体集合类型 
  186.         /// 要执行的查询语句    
  187.         /// 执行SQL查询语句所需要的参数    
  188.         /// 执行的SQL语句的类型 
  189.         ///  
  190.         public T QueryForObject(string sql, IList parameters, CommandType commandType) where T : new() 
  191.         { 
  192.             return QueryForList(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.         ///  
  210.         /// 创建一个DbCommand对象 
  211.         ///  
  212.         /// 要执行的查询语句    
  213.         /// 执行SQL查询语句所需要的参数 
  214.         /// 执行的SQL语句的类型 
  215.         ///  
  216.         private DbCommand CreateDbCommand(string sql, IList 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.     ///  
  235.     /// 数据库类型枚举 
  236.     ///  
  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.     ///  
  252.     /// DbProviderFactory工厂类 
  253.     ///  
  254.     public class ProviderFactory 
  255.     { 
  256.         private static Dictionary<>string> providerInvariantNames = new Dictionary<>string>(); 
  257.         private static Dictionary providerFactoies = new Dictionary(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.         ///  
  274.         /// 获取指定数据库类型对应的程序集名称 
  275.         ///  
  276.         /// 数据库类型枚举 
  277.         ///  
  278.         public static string GetProviderInvariantName(DbProviderType providerType) 
  279.         { 
  280.             return providerInvariantNames[providerType]; 
  281.         } 
  282.         ///  
  283.         /// 获取指定类型的数据库对应的DbProviderFactory 
  284.         ///  
  285.         /// 数据库类型枚举 
  286.         ///  
  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.         ///  
  297.         /// 加载指定数据库类型的DbProviderFactory 
  298.         ///  
  299.         /// 数据库类型枚举 
  300.         ///  
  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 

本文出自 “周公(周金桥)的专栏” 博客,请务必保留此出处http://zhoufoxcn.blog.51cto.com/792419/832631

文章评论

2012-04-26
收藏之

2012-05-18
暂时的水平,有的地方还看不懂

2012-07-24
没有SQL参数化,存在sql注入

2012-07-24
''<>&

2012-07-26
回复 123:[3楼]

兄弟,认真看完再评论也不迟的,string sql, IList parameters, CommandType commandType,这么个参数列表,还没有参数化?

2012-09-13
周老师好,你的第二点泛型运行时错误,是指哪里呢?我没看出来。

2012-11-22
望评委能够给予支持和鼓励http://yiluohuanghun.blog.51cto.com谢谢

2012-11-22
回复 驿落黄昏:[7楼]

为什么不直接给投票地址呢?

2013-01-07
写的不多

2013-01-07
写的不错

2014-11-22
sealed class怎么调用里面的方法?

2014-12-10
回复 vsceo:[11楼]

为什么sealed class就不能调用了?sealed只是限制了不能继承而已。

2015-06-11
不错,学习了哦

2015-08-15
好好学一下篇文章.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多