ADO.NET快速上手实践总结

开发 后端
本文将介绍一下ADO.NET快速上手方面的内容,也希望通过介绍作者的个人经历,给大家更好的理解ADO有帮助。

本文希望能给大家一些启发。前言:这两天重温经典,对ADO.NET的东西稍微深入的了解了一下,顺便写点代码练练手,全当是复习笔记吧。

一、简单说说ADO.NET的5大常用对象

既然说ADO.NET,当然不能免俗地要提到5大常用对象。本文不会对ADO.NET的5大对象和它们的关系进行过多阐释,不过我们应该对下面这张图的结构有个了解:

架构图

关于上图图示中的5大对象,经常做以数据为驱动的mis系统的童鞋应该不会陌生。本文一笔带过。下面我们一步一步实现以ADO.NET为核心的数据访问程序。

二、数据访问持久化层

1、IDbOperation接口

  1. using System.Collections.Generic;  
  2. using System.Data;  
  3. using System.Data.Common;  
  4. namespace AdoNetDataAccess.Core.Contract  
  5. {  
  6.     public interface IDbOperation  
  7.     {  
  8.         DbCommand CreateDbCommd(DbConnection sqlConn, DbTransaction transaction, string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  9.         DbParameter CreateDbPrameter(string paramName, object paramValue);  
  10.         DbDataReader ExecuteReader(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  11.         DataTable FillDataTable(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  12.         DataSet FillDataSet(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  13.         object ExecuteScalar(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  14.        int ExecuteNonQuery(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  15.         /// <summary>  
  16.         /// 批量插入  
  17.         /// </summary>  
  18.         /// <param name="tableName">表名称</param>  
  19.         /// <param name="dt">组装好的要批量导入的datatable</param>  
  20.         /// <returns></returns>  
  21.         bool ExecuteBatchInsert(string tableName, int batchSize, int copyTimeout, DataTable dt);  
  22.         void OpenConnection();  
  23.         void CloseConnection();  
  24.     }  

上面的接口包括增删改查,批量插入以及数据库连接对象的连接和关闭等常用操作,您可以根据命名和参数轻松理解函数的含义。根据楼猪的开发经验,对于平时的数据库操作,上述方法差不多够用了。当然您也可以按照自己需要,重写组织添加其他函数。

2、针对一种数据源的数据操作实现

底层的数据操作接口定义好后,就要针对一种数据源,具体实现上述的数据操作。这里楼猪选择了Sql Server。我们也可以实现其他数据源的数据访问操作,按照配置,利用抽象工厂动态反射选择是哪一种数据源的实现。这里按下不表,有心的童鞋自己可以动手一试。下面是具体的实现:

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Data;  
  4. using System.Data.Common;  
  5. using System.Data.SqlClient;  
  6. using System.Transactions;  
  7. namespace AdoNetDataAccess.Core.Implement  
  8. {  
  9.     using AdoNetDataAccess.Core.Contract;  
  10.  
  11.     public class SqlServer : IDbOperation, IDisposable  
  12.     {  
  13.         private int cmdTimeOut = 60;  
  14.         private DbConnection sqlConn = null;  
  15.         private DbCommand cmd = null;  
  16.  
  17.         private SqlServer()  
  18.         {  
  19.         }  
  20.         public SqlServer(string sqlConStr)  
  21.         {  
  22.             sqlConn = new SqlConnection(sqlConStr);  
  23.             cmdTimeOut = sqlConn.ConnectionTimeout;  
  24.         }  
  25.         public SqlServer(string sqlConStr, int timeOut)  
  26.         {  
  27.             sqlConn = new SqlConnection(sqlConStr);  
  28.             if (timeOut < 0)  
  29.             {  
  30.                 timeOut = sqlConn.ConnectionTimeout;  
  31.             }  
  32.             cmdTimeOut = timeOut;  
  33.         }  
  34.         #region contract method  
  35.         public DbCommand CreateDbCommd(DbConnection sqlConn, DbTransaction transaction, string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  36.         {  
  37.             DbCommand cmd = new SqlCommand();  
  38.             cmd.Connection = sqlConn;  
  39.             cmd.CommandText = sqlStr;  
  40.             cmd.CommandType = cmdType;  
  41.             if (transaction != null)  
  42.             {  
  43.                 cmd.Transaction = transaction;  
  44.             }  
  45.             if (listParams != null && listParams.Count > 0)  
  46.             {  
  47.                 cmd.Parameters.AddRange(listParams.ToArray());  
  48.             }  
  49.             cmd.CommandTimeout = cmdTimeOut;  
  50.             OpenConnection();  
  51.             return cmd;  
  52.         }  
  53.  
  54.         public DbParameter CreateDbPrameter(string paramName, object paramValue)  
  55.         {  
  56.             SqlParameter sp = new SqlParameter(paramName, paramValue);  
  57.             return sp;  
  58.         }  
  59.  
  60.         public DbDataReader ExecuteReader(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  61.         {  
  62.             DbDataReader rdr = null;  
  63.             try 
  64.             {  
  65.                 OpenConnection();  
  66.                 cmd = CreateDbCommd(sqlConn, null, sqlStr, cmdType, listParams);  
  67.                 rdr = cmd.ExecuteReader();  
  68.             }  
  69.             catch (Exception ex)  
  70.             {  
  71.                 throw ex;  
  72.             }  
  73.             return rdr;  
  74.         }  
  75.  
  76.         public DataTable FillDataTable(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  77.         {  
  78.             OpenConnection();  
  79.             DbTransaction trans = sqlConn.BeginTransaction();  
  80.             DbCommand cmd = CreateDbCommd(sqlConn, trans, sqlStr, cmdType, listParams);  
  81.             SqlDataAdapter sqlDataAdpter = new SqlDataAdapter(cmd as SqlCommand);  
  82.             DataTable dt = new DataTable();  
  83.             try 
  84.             {  
  85.                 sqlDataAdpter.Fill(dt);  
  86.                 trans.Commit();  
  87.             }  
  88.             catch (Exception e)  
  89.             {  
  90.                 trans.Rollback();  
  91.                 throw new Exception("执行数据库操作失败, sql: " + sqlStr, e);  
  92.             }  
  93.             finally 
  94.             {  
  95.                 sqlDataAdpter.Dispose();  
  96.                 cmd.Dispose();  
  97.                 trans.Dispose();  
  98.                 CloseConnection();  
  99.             }  
  100.             return dt;  
  101.         }  
  102.  
  103.         public DataSet FillDataSet(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  104.         {  
  105.             OpenConnection();  
  106.             DbTransaction trans = sqlConn.BeginTransaction();  
  107.             DbCommand cmd = CreateDbCommd(sqlConn, trans, sqlStr, cmdType, listParams);  
  108.             SqlDataAdapter sqlDataAdpter = new SqlDataAdapter(cmd as SqlCommand);  
  109.             DataSet ds = new DataSet();  
  110.             try 
  111.             {  
  112.                 sqlDataAdpter.Fill(ds);  
  113.                 trans.Commit();  
  114.             }  
  115.             catch (Exception e)  
  116.             {  
  117.                 trans.Rollback();  
  118.                 throw new Exception("执行数据库操作失败, sql: " + sqlStr, e);  
  119.             }  
  120.             finally 
  121.             {  
  122.                 sqlDataAdpter.Dispose();  
  123.                 cmd.Dispose();  
  124.                 trans.Dispose();  
  125.                 CloseConnection();  
  126.             }  
  127.             return ds;  
  128.         }  
  129.  
  130.         public object ExecuteScalar(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  131.         {  
  132.             object result = null;  
  133.             OpenConnection();  
  134.             DbTransaction trans = sqlConn.BeginTransaction();  
  135.             try 
  136.             {  
  137.                 cmd = CreateDbCommd(sqlConn, trans, sqlStr, cmdType, listParams);  
  138.                 result = cmd.ExecuteScalar();  
  139.                 trans.Commit();  
  140.             }  
  141.             catch (Exception e)  
  142.             {  
  143.                 trans.Rollback();  
  144.                 throw new Exception("执行数据库操作失败, sql: " + sqlStr, e);  
  145.             }  
  146.             finally 
  147.             {  
  148.                 trans.Dispose();  
  149.                 CloseConnection();  
  150.             }  
  151.             return result;  
  152.         }  
  153.  
  154.         public int ExecuteNonQuery(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  155.         {  
  156.             int result = -1;  
  157.             OpenConnection();  
  158.             DbTransaction trans = sqlConn.BeginTransaction();  
  159.             try 
  160.             {  
  161.                 cmd = CreateDbCommd(sqlConn, trans, sqlStr, cmdType, listParams);  
  162.                 result = cmd.ExecuteNonQuery();  
  163.                 trans.Commit();  
  164.             }  
  165.             catch (Exception e)  
  166.             {  
  167.                 trans.Rollback();  
  168.                 throw new Exception("执行数据库操作失败, sql: " + sqlStr, e);  
  169.             }  
  170.             finally 
  171.             {  
  172.                 trans.Dispose();  
  173.                 CloseConnection();  
  174.             }  
  175.             return result;  
  176.         }  
  177.  
  178.         /// <summary>  
  179.         /// 批量插入  
  180.         /// </summary>  
  181.         /// <param name="tableName"></param>  
  182.         /// <param name="batchSize"></param>  
  183.         /// <param name="copyTimeout"></param>  
  184.         /// <param name="dt"></param>  
  185.         /// <returns></returns>  
  186.         public bool ExecuteBatchInsert(string tableName, int batchSize, int copyTimeout, DataTable dt)  
  187.         {  
  188.             bool flag = false;  
  189.             try 
  190.             {  
  191.                 using (TransactionScope scope = new TransactionScope())  
  192.                 {  
  193.                     OpenConnection();  
  194.                     using (SqlBulkCopy sbc = new SqlBulkCopy(sqlConn as SqlConnection))  
  195.                     {  
  196.                         //服务器上目标表的名称  
  197.                         sbc.DestinationTableName = tableName;  
  198.                         sbc.BatchSize = batchSize;  
  199.                         sbc.BulkCopyTimeout = copyTimeout;  
  200.                         for (int i = 0; i < dt.Columns.Count; i++)  
  201.                         {  
  202.                             //列映射定义数据源中的列和目标表中的列之间的关系  
  203.                             sbc.ColumnMappings.Add(dt.Columns[i].ColumnName, dt.Columns[i].ColumnName);  
  204.                         }  
  205.                         sbc.WriteToServer(dt);  
  206.                         flag = true;  
  207.                         scope.Complete();//有效的事务  
  208.                     }  
  209.                 }  
  210.             }  
  211.             catch (Exception ex)  
  212.             {  
  213.                 throw ex;  
  214.             }  
  215.             return flag;  
  216.         }  
  217.         public void OpenConnection()  
  218.         {  
  219.             if (sqlConn.State == ConnectionState.Broken || sqlConn.State == ConnectionState.Closed)  
  220.                 sqlConn.Open();  
  221.         }  
  222.         public void CloseConnection()  
  223.         {  
  224.             sqlConn.Close();  
  225.         }  
  226.         #endregion  
  227.         #region dispose method  
  228.  
  229.         /// <summary>  
  230.         /// dispose接口方法  
  231.         /// </summary>  
  232.         public void Dispose()  
  233.         {  
  234.         }  
  235.         #endregion  
  236.     }  
 
 
 

到这里,我们实现了SqlServer类里的方法,对Ms SqlServer数据库我们就已经可以进行简单的基础的CRUD操作了。

三、简单直观的对象实体转换

在第二步中,我们已经实现了简单的数据CRUD操作。根据楼猪使用ORM的经验和习惯,我们也应该对一些查询结果进行转换,因为以类的组织方式比直接呈现ADO.NET对象更容易让人接受,效率高低反在其次。下面利用常见的反射原理,简单实现一个对象实体转换器ModelConverter类: 

  1. using System;  
  2. using System.Collections;  
  3. using System.Collections.Generic;  
  4. using System.Data;  
  5. using System.Data.Common;  
  6. using System.Reflection;  
  7. using System.Threading;  
  8. namespace AdoNetDataAccess.Core.Obj2Model  
  9. {  
  10.     using AdoNetDataAccess.Core.Contract;  
  11.  
  12.     public sealed class ModelConverter  
  13.     {  
  14.         private static readonly object objSync = new object();  
  15.  
  16.         #region query for list  
  17.  
  18.         /// <summary>  
  19.         /// 查询数据表项并转换为对应实体  
  20.         /// </summary>  
  21.         /// <typeparam name="T"></typeparam>  
  22.         /// <param name="objType"></param>  
  23.         /// <param name="rdr"></param>  
  24.         /// <returns></returns>  
  25.         public static IList<T> QueryForList<T>(string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType, IDbOperation dbOperation)  
  26.             where T : classnew()  
  27.         {  
  28.             IDataReader rdr = dbOperation.ExecuteReader(sqlStr, cmdType, listParams);  
  29.             IList<T> listModels = new List<T>();  
  30.             try 
  31.             {  
  32.                 Monitor.Enter(objSync);  
  33.                 Hashtable ht = CreateHashColumnName(rdr);  
  34.                 while (rdr.Read())  
  35.                 {  
  36.                     Object obj = Activator.CreateInstance(objType);  
  37.                     PropertyInfo[] properties = objType.GetProperties();  
  38.                     foreach (PropertyInfo propInfo in properties)  
  39.                     {  
  40.                         string columnName = propInfo.Name.ToUpper();  
  41.                         if (ht.ContainsKey(columnName) == false)  
  42.                         {  
  43.                             continue;  
  44.                         }  
  45.                         int index = rdr.GetOrdinal(propInfo.Name);  
  46.                         object columnValue = rdr.GetValue(index);  
  47.                         if (columnValue != System.DBNull.Value)  
  48.                         {  
  49.                             SetValue(propInfo, obj, columnValue);  
  50.                         }  
  51.                     }  
  52.                     T model = default(T);  
  53.                     model = obj as T;  
  54.                     listModels.Add(model);  
  55.                 }  
  56.             }  
  57.             finally 
  58.             {  
  59.                 rdr.Close();  
  60.                 rdr.Dispose();  
  61.                 Monitor.Exit(objSync);  
  62.             }  
  63.             return listModels;  
  64.         }  
  65.  
  66.         #endregion  
  67.  
  68.         #region query for dictionary  
  69.  
  70.         /// <summary>  
  71.         /// 查询数据表项并转换为对应实体  
  72.         /// </summary>  
  73.         /// <typeparam name="K"></typeparam>  
  74.         /// <typeparam name="T"></typeparam>  
  75.         /// <param name="key">字典对应key列名</param>  
  76.         /// <param name="objType"></param>  
  77.         /// <param name="rdr"></param>  
  78.         /// <returns></returns>  
  79.         public static IDictionary<K, T> QueryForDictionary<K, T>
  80. (string key, string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType, IDbOperation dbOperation)  
  81.             where T : classnew()  
  82.         {  
  83.             IDataReader rdr = dbOperation.ExecuteReader(sqlStr, cmdType, listParams);  
  84.             IDictionary<K, T> dictModels = new Dictionary<K, T>();  
  85.             try 
  86.             {  
  87.                 Monitor.Enter(objSync);  
  88.                 Hashtable ht = CreateHashColumnName(rdr);  
  89.                 while (rdr.Read())  
  90.                 {  
  91.                     Object obj = Activator.CreateInstance(objType);  
  92.                     PropertyInfo[] properties = objType.GetProperties();  
  93.                     object dictKey = null;  
  94.                     foreach (PropertyInfo propInfo in properties)  
  95.                     {  
  96.                         string columnName = propInfo.Name.ToUpper();  
  97.                         if (ht.ContainsKey(columnName) == false)  
  98.                         {  
  99.                             continue;  
  100.                         }  
  101.                         int index = rdr.GetOrdinal(propInfo.Name);  
  102.                         object columnValue = rdr.GetValue(index);  
  103.                         if (columnValue != System.DBNull.Value)  
  104.                         {  
  105.                             SetValue(propInfo, obj, columnValue);  
  106.                             if (string.Compare(columnName, key.ToUpper()) == 0)  
  107.                             {  
  108.                                 dictKey = columnValue;  
  109.                             }  
  110.                         }  
  111.                     }  
  112.                     T model = default(T);  
  113.                     model = obj as T;  
  114.                     K objKey = (K)dictKey;  
  115.                     dictModels.Add(objKey, model);  
  116.                 }  
  117.             }  
  118.             finally 
  119.             {  
  120.                 rdr.Close();  
  121.                 rdr.Dispose();  
  122.                 Monitor.Exit(objSync);  
  123.             }  
  124.             return dictModels;  
  125.         }  
  126.  
  127.         #endregion  
  128.  
  129.         #region internal util  
  130.  
  131.         private static Hashtable CreateHashColumnName(IDataReader rdr)  
  132.         {  
  133.             int len = rdr.FieldCount;  
  134.             Hashtable ht = new Hashtable(len);  
  135.             for (int i = 0; i < len; i++)  
  136.             {  
  137.                 string columnName = rdr.GetName(i).ToUpper(); //不区分大小写  
  138.                 string columnRealName = rdr.GetName(i);  
  139.                 if (ht.ContainsKey(columnName) == false)  
  140.                 {  
  141.                     ht.Add(columnName, columnRealName);  
  142.                 }  
  143.             }  
  144.             return ht;  
  145.         }  
  146.  
  147.         private static void SetValue(PropertyInfo propInfo, Object obj, object objValue)  
  148.         {  
  149.             try 
  150.             {  
  151.                 propInfo.SetValue(obj, objValue, null);  
  152.             }  
  153.             catch 
  154.             {  
  155.                 object realValue = null;  
  156.                 try 
  157.                 {  
  158.                     realValue = Convert.ChangeType(objValue, propInfo.PropertyType);  
  159.                     propInfo.SetValue(obj, realValue, null);  
  160.                 }  
  161.                 catch (Exception ex)  
  162.                 {  
  163.                     string err = ex.Message;  
  164.                     //throw ex; //在数据库数据有不符合规范的情况下应该及时抛出异常  
  165.                 }  
  166.             }  
  167.         }  
  168.  
  169.         #endregion  
  170.     }  

到这里,简单的数据访问持久化层就实现了。下面模仿楼猪使用的IBatis.net,写个伪SqlMapper,改善一下调用形式,丰富一下调用方法,让方法辨识度更高。

四、实现伪SqlMapper

1、BaseMapper类

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Data;  
  4. using System.Data.Common;  
  5. using System.Data.SqlClient;  
  6. namespace AdoNetDataAccess.Mapper  
  7. {  
  8.     using AdoNetDataAccess.Core.Contract;  
  9.     public abstract class BaseMapper  
  10.     {  
  11.         public IDbOperation CurrentDbOperation;  
  12.         #region query for list  
  13.         public abstract IList<T> QueryForList<T>(string sqlStr)  
  14.   where T : classnew();  
  15.  
  16.         public abstract IList<T> QueryForList<T>(string sqlStr, Type objType)  
  17. where T : classnew();  public abstract IList<T> QueryForList<T>(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  18.        where T : classnew();  
  19.         public abstract IList<T> QueryForList<T>
  20. (string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType)  
  21.        where T : classnew();  
  22.        #endregion  
  23.        #region query for dictionary  
  24.         public abstract IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr)  
  25.             where T : classnew();  
  26.         public abstract IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, Type objType)  
  27.     where T : classnew();  
  28.         public abstract IDictionary<K, T> QueryForDictionary<K, T>
  29. (string key, string sqlStr, CommandType cmdType, Type objType)  
  30.             where T : classnew();  
  31.         public abstract IDictionary<K, T> QueryForDictionary<K, T>
  32. (string key, string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType)  
  33.                     where T : classnew();  
  34.         #endregion  
  35.         #region dataset datatable  
  36.         public abstract DataTable FillDataTable(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  37.         public abstract DataSet FillDataSet(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  38.         #endregion  
  39.         #region ExecuteScalar  
  40.         public abstract object ExecuteScalar(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  41.         #endregion  
  42.         #region insert  
  43.         public abstract int Insert(string sqlStr);  
  44.        public abstract int Insert(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  45.         public abstract bool BatchInsert(string tableName, int batchSize, int copyTimeout, DataTable dt);  
  46.         #endregion  
  47.         #region delete  
  48.         public abstract int Delete(string sqlStr);  
  49.         public abstract int Delete(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  50.         #endregion  
  51.         #region update  
  52.         public abstract int Update(string sqlStr);  
  53.        public abstract int Update(string sqlStr, CommandType cmdType, List<DbParameter> listParams);  
  54.         #endregion  
  55.     }  

上面代码中的方法您是不是很熟悉呢? 呵呵,使用IBatis.net 的童鞋应该会和楼猪产生更多的共鸣。

2、SqlMapper类

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Data;  
  4. using System.Data.Common;  
  5. namespace AdoNetDataAccess.Mapper  
  6. {  
  7.     using AdoNetDataAccess.Core.Contract;  
  8.     using AdoNetDataAccess.Core.Obj2Model;  
  9.     public class SqlMapper : BaseMapper  
  10.     {  
  11.         private SqlMapper()  
  12.         {   }  
  13.         public SqlMapper(IDbOperation dbOperation)  
  14.         {  
  15.             this.CurrentDbOperation = dbOperation;  
  16.         }  
  17.  
  18.         #region query for list  
  19.         public override IList<T> QueryForList<T>(string sqlStr)  
  20.         {  
  21.             return QueryForList<T>(sqlStr, CommandType.Text, nulltypeof(T));  
  22.         }  
  23.  
  24.         public override IList<T> QueryForList<T>(string sqlStr, Type objType)  
  25.         {  
  26.             return QueryForList<T>(sqlStr, CommandType.Text, null, objType);  
  27.         }  
  28.         public override IList<T> QueryForList<T>(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  29.         {  
  30.             return QueryForList<T>(sqlStr, cmdType, listParams, typeof(T));  
  31.         }  
  32.         public override IList<T> QueryForList<T>(string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType)  
  33.         {  
  34.             return ModelConverter.QueryForList<T>(sqlStr, cmdType, listParams, objType, this.CurrentDbOperation);  
  35.         }  
  36.         #endregion  
  37.         #region query for dictionary  
  38.         public override IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr)  
  39.         {  
  40.             return QueryForDictionary<K, T>(key, sqlStr, CommandType.Text, nulltypeof(T));  
  41.         }  
  42.         public override IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, Type objType)  
  43.         {  
  44.             return QueryForDictionary<K, T>(key, sqlStr, CommandType.Text, null, objType);  
  45.         }  
  46.         public override IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, CommandType cmdType, Type objType)  
  47.         {  
  48.             return QueryForDictionary<K, T>(key, sqlStr, cmdType, null, objType);  
  49.         }  
  50.         public override IDictionary<K, T> QueryForDictionary<K, T>
  51. (string key, string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType)  
  52.         {  
  53.             return ModelConverter.QueryForDictionary<K, T>(key, sqlStr, cmdType, listParams, objType, this.CurrentDbOperation);  
  54.         }  
  55.         #endregion  
  56.         #region dataset datatable  
  57.         public override DataTable FillDataTable(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  58.         {  
  59.             return this.CurrentDbOperation.FillDataTable(sqlStr, cmdType, listParams);  
  60.         }  
  61.         public override DataSet FillDataSet(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  62.         {  
  63.             return this.CurrentDbOperation.FillDataSet(sqlStr, cmdType, listParams);  
  64.         }  
  65.        #endregion  
  66.         #region ExecuteScalar  
  67.   public override object ExecuteScalar(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  68.         {  
  69.             return this.CurrentDbOperation.ExecuteScalar(sqlStr, cmdType, listParams);  
  70.         }  
  71.         #endregion  
  72.         #region insert  
  73.         public override int Insert(string sqlStr)  
  74.         {  
  75.             object obj = ExecuteScalar(sqlStr, CommandType.Text, null);  
  76.             int id = obj == null ? 0 : int.Parse(obj.ToString());  
  77.             return id;  
  78.         }  
  79.  public override int Insert(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  80.         {  
  81.             object obj = ExecuteScalar(sqlStr, cmdType, listParams);  
  82.             int id = obj == null ? 0 : int.Parse(obj.ToString());  
  83.             return id;  
  84.         }  
  85.         /// <summary>  
  86.         /// 批量插入  
  87.         /// </summary>  
  88.         /// <param name="tableName"></param>  
  89.         /// <param name="batchSize"></param>  
  90.         /// <param name="copyTimeout"></param>  
  91.         /// <param name="dt"></param>  
  92.         /// <returns></returns>  
  93.  public override bool BatchInsert(string tableName, int batchSize, int copyTimeout, DataTable dt)  
  94.         {  
  95.    return this.CurrentDbOperation.ExecuteBatchInsert(tableName, batchSize, copyTimeout, dt);  
  96.         }  
  97.         #endregion  
  98.         #region delete  
  99.         public override int Delete(string sqlStr)  
  100.         {  
  101.             return CommitSql(sqlStr, CommandType.Text, null);  
  102.         }  
  103.   public override int Delete(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  104.         {  
  105.             return CommitSql(sqlStr, cmdType, listParams);  
  106.         }  
  107.         #endregion  
  108.         #region update  
  109.         public override int Update(string sqlStr)  
  110.         {  
  111.             return CommitSql(sqlStr, CommandType.Text, null);  
  112.         }  
  113.  public override int Update(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  114.         {  
  115.             return CommitSql(sqlStr, cmdType, listParams);  
  116.         }  
  117.         #endregion  
  118.         #region commit and execute sql  
  119.         private int CommitSql(string sqlStr, CommandType cmdType, List<DbParameter> listParams)  
  120.         {  
  121.             return this.CurrentDbOperation.ExecuteNonQuery(sqlStr, cmdType, listParams);  
  122.         }  
  123.  
  124.         #endregion  
  125.         #region  dbparameter  
  126.         public DbParameter CreateParameter(string paraName, object paramValue)  
  127.         {  
  128.             return this.CurrentDbOperation.CreateDbPrameter(paraName, paramValue);  
  129.         }  
  130.  
  131.         public List<DbParameter> CreateParameterList(string[] paraNames, object[] paramValues)  
  132.         {  
  133.             List<DbParameter> listParams = new List<DbParameter>();  
  134.             try 
  135.             {  
  136.                 if (paraNames.Length != paramValues.Length)  
  137.                 {  
  138.                     throw new Exception("Param name and value is not equal.");  
  139.                 }  
  140.                 for (int i = 0; i < paraNames.Length; i++)  
  141.                 {  
  142.                     DbParameter param = CreateParameter(paraNames[i], paramValues[i]);  
  143.                     listParams.Add(param);  
  144.                 }  
  145.             }  
  146.             catch (Exception ex)  
  147.             {  
  148.                 throw ex;  
  149.             }  
  150.             return listParams;  
  151.         }  
  152.         #endregion  
  153.     }  

上面的方法丰富实现了CRUD的常见操作,其实主要还是调用了IDbOperation接口和方法。

五、dal层数据访问实现

在这里我们使用前一篇文章里实现的数据持久化层和伪SqlMapper对象,实现数据操作。下面我们来看看Dal下核心的Dao如何实现:

还记得我们在IBatis.net下面的dao类是怎么实现的吗?没错,我们根据一个基类BaseDAO和它的构造函数,实现dao的配置加载。但是楼猪的实现没有那么复杂和强大,本文的实现其实就是通过BaseDAO和构造函数获取数据库连接对象的key,初始化一个SqlMapper,然后利用SqlMapper对象进行基本的CRUD等等数据操作。那么我们如何利用BaseDAO和构造函数就像以前在IBatis.net系列文章里的提到的Dal层下那样进行SqlMapper的初始化呢?

1、在AdoNetDataAccess.Mapper下我们定义公共的BaseDAO类

  1. namespace AdoNetDataAccess.Mapper  
  2. {  
  3.     public abstract class BaseDAO  
  4.     {  
  5.         #region Properties  
  6.         public SqlMapper SqlMapper { getset; }  
  7.         #endregion  
  8.         #region Constructor  
  9.         private BaseDAO()  
  10.         {  
  11.         }  
  12.         /// <summary>  
  13.         /// SqlMapper属性适用  
  14.         /// </summary>  
  15.         /// <param name="mapperName"></param>  
  16.         public BaseDAO(string mapperName)  
  17.         {  
  18.             this.SqlMapper = MapperUtill.GetMapper(mapperName);  
  19.         }  
  20.         #endregion  
  21.     }  

2、初始化SqlMapper的实用类

  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Configuration;  
  4.  
  5. namespace AdoNetDataAccess.Mapper  
  6. {  
  7.     using AdoNetDataAccess.Core.Contract;  
  8.     using AdoNetDataAccess.Core.Implement;  
  9.  
  10.     public sealed class MapperUtill  
  11.     {  
  12.         #region fields  
  13.  
  14.         public static string currentSqlKey = "sqlConn";  
  15.  
  16.         public static int cmdTimeOut = 15;  
  17.  
  18.         private static readonly object objSync = new object();  
  19.  
  20.         private static readonly IDictionary<string, SqlMapper> dictMappers = new Dictionary<string, SqlMapper>();  
  21.  
  22.         #endregion  
  23.  
  24.         #region constructor and methods  
  25.  
  26.         private MapperUtill()  
  27.         {  
  28.  
  29.         }  
  30.  
  31.         static MapperUtill()  
  32.         {  
  33.             try 
  34.             {  
  35.                 cmdTimeOut = int.Parse(ConfigurationManager.AppSettings["db_timeOut"]);  
  36.             }  
  37.             catch 
  38.             {  
  39.                 cmdTimeOut = 15;  
  40.             }  
  41.             //实例化SqlDbMapper  
  42.             for (int i = 0; i < ConfigurationManager.ConnectionStrings.Count; i++)  
  43.             {  
  44.                 string key = ConfigurationManager.ConnectionStrings[i].Name;  
  45.                 string value = ConfigurationManager.ConnectionStrings[i].ConnectionString;  
  46.                 CreateMapper(key, value, cmdTimeOut);  
  47.             }  
  48.         }  
  49.  
  50.         public static SqlMapper GetSqlMapper(string key)  
  51.         {  
  52.             return MapperUtill.GetMapper(key);  
  53.         }  
  54.  
  55.         public static SqlMapper GetCurrentSqlMapper()  
  56.         {  
  57.             return MapperUtill.GetMapper(currentSqlKey);  
  58.         }  
  59.  
  60.         public static void CreateMapper(string connKey, string sqlConStr, int connTimeOut)  
  61.         {  
  62.             IDbOperation operation = new SqlServer(sqlConStr, connTimeOut);  
  63.             SqlMapper mapper = new SqlMapper(operation);  
  64.             dictMappers.Add(connKey.ToUpper().Trim(), mapper);//不区分大小写  
  65.         }  
  66.  
  67.         public static SqlMapper GetMapper(string sqlConKey)  
  68.         {  
  69.             if (string.IsNullOrEmpty(sqlConKey))  
  70.             {  
  71.                 throw new Exception("数据库连接字符串主键为空!");  
  72.             }  
  73.             sqlConKey = sqlConKey.ToUpper();//不区分大小写  
  74.             SqlMapper mapper = null;  
  75.             if (dictMappers.ContainsKey(sqlConKey))  
  76.             {  
  77.                 mapper = dictMappers[sqlConKey];  
  78.             }  
  79.             else 
  80.             {  
  81.                 throw new Exception(string.Format("没有{0}所对应的数据库连接", sqlConKey));  
  82.             }  
  83.             return mapper;  
  84.         }  
  85.  
  86.         /// <summary>  
  87.         /// 释放所有  
  88.         /// </summary>  
  89.         public void Release()  
  90.         {  
  91.             foreach (KeyValuePair<string, SqlMapper> kv in dictMappers)  
  92.             {  
  93.                 SqlMapper mapper = kv.Value;  
  94.                 if (mapper == null)  
  95.                 {  
  96.                     continue;  
  97.                 }  
  98.                 mapper.CurrentDbOperation.CloseConnection();  
  99.             }  
  100.             dictMappers.Clear();  
  101.         }  
  102.  
  103.         #endregion  
  104.  
  105.     }  

这个实用类的重要作用就是初始化配置文件里connectionStrings配置节点,以获取sql连接对象必须的连接字符串。

3、PersonDao类

下面就是针对具体的Person表的数据操作了:

  1. using System.Collections.Generic;  
  2. using System.Data;  
  3.  
  4. namespace AdoNetDataAccess.Dal.Dao  
  5. {  
  6.     using AdoNetDataAccess.Dal.Model;  
  7.     using AdoNetDataAccess.Dal.Utility;  
  8.     using AdoNetDataAccess.Mapper;  
  9.  
  10.     public class PersonDao : BaseDAO  
  11.     {  
  12.         public PersonDao()  
  13.             : base("sqlConn")//sqlConn是<connectionStrings>配置节点的一个name  
  14.         {  
  15.         }  
  16.  
  17.         public int Insert(string sqlInsert)  
  18.         {  
  19.             int id = this.SqlMapper.Insert(sqlInsert);  
  20.             //object obj = this.SqlMapper.ExecuteScalar(sqlInsert, System.Data.CommandType.Text, null);  
  21.             return id;  
  22.         }  
  23.  
  24.         public bool BatchInsert(IList<Person> listModels)  
  25.         {  
  26.             int batchSize = 50000;  
  27.             int copyTimeOut = 60;  
  28.             DataTable dt = DataTableHelper.CreateTable<Person>(listModels);  
  29.             bool flag = this.SqlMapper.BatchInsert(typeof(Person).Name, batchSize, copyTimeOut, dt);  
  30.             return flag;  
  31.         }  
  32.  
  33.         public int Update(string sqlUpdate)  
  34.         {  
  35.             int result = this.SqlMapper.Update(sqlUpdate);  
  36.             return result;  
  37.         }  
  38.  
  39.         public IList<Person> SelectPersons(string sqlSelect)  
  40.         {  
  41.             IList<Person> listPersons = this.SqlMapper.QueryForList<Person>(sqlSelect);  
  42.             return listPersons;  
  43.         }  
  44.  
  45.         public IDictionary<int, Person> SelectDictPersons(string sqlSelect)  
  46.         {  
  47.             IDictionary<int, Person> dictPersons = this.SqlMapper.QueryForDictionary<int, Person>("Id", sqlSelect);  
  48.             return dictPersons;  
  49.         }  
  50.  
  51.         public DataTable SelectPersonTable(string sqlSelect)  
  52.         {  
  53.             DataTable dt = this.SqlMapper.FillDataTable(sqlSelect, CommandType.Text, null);  
  54.             return dt;  
  55.         }  
  56.  
  57.         public DataSet SelectPersonDataSet(string sqlSelect)  
  58.         {  
  59.             DataSet ds = this.SqlMapper.FillDataSet(sqlSelect, CommandType.Text, null);  
  60.             return ds;  
  61.         }  
  62.  
  63.         public int Delete(string sqlDelete)  
  64.         {  
  65.             int result = this.SqlMapper.Delete(sqlDelete);  
  66.             return result;  
  67.         }  
  68.  
  69.     }  

到这里,一个dao类操作就实现了。然后我们按步就班实现对外调用的服务接口。在表现层调用吧。

六、表现层的调用

1、配置文件

  1. <appSettings> 
  2.   <add key="db_timeOut" value="5000"/> 
  3. </appSettings> 
  4. <connectionStrings> 
  5.   <add name="sqlConn" connectionString="Data Source=.\sqlexpress; Initial Catalog=TestDb; User Id=sa; Password=123456;"/> 
  6.   <add name="sqlConnStr1" connectionString="Data Source=.\sqlexpress; Initial Catalog=TestDb; User Id=sa; Password=123456;"/> 
  7.   <add name="sqlConnStr2" connectionString="Data Source=.\sqlexpress; Initial Catalog=TestDb; User Id=sa; Password=123456;"/> 
  8. </connectionStrings> 

其中,connectionString是必须的,如果没有,我们无法加载调用可用的SqlMapper。

2、CRUD操作测试

  1. using System;  
  2. using System.Collections;  
  3. using System.Collections.Generic;  
  4. using System.Data;  
  5.  
  6. namespace OOXXWebApp  
  7. {  
  8.     using AdoNetDataAccess.Dal;  
  9.     using AdoNetDataAccess.Dal.Model;  
  10.  
  11.     public partial class _Default : System.Web.UI.Page  
  12.     {  
  13.         protected void Page_Load(object sender, EventArgs e)  
  14.         {  
  15.             if (!IsPostBack)  
  16.             {  
  17.                 //增删改查测试  
  18.                 string sqlInsert = "INSERT Person (FirstName,LastName,Weight,Height) VALUES( 'jeff','wong',70,180) SELECT @@IDENTITY FROM Person(NOLOCK)";  
  19.                 string sqlUpdate = "UPDATE Person SET Height=178 WHERE Id=1";  
  20.                 string sqlSelect = "SELECT TOP 100 * FROM Person(NOLOCK)";  
  21.                 string sqlDelete = "DELETE Person  WHERE Id>10 AND Id<100";  
  22.  
  23.                 IList<Person> listModels = new List<Person>();  
  24.                 for (int i = 0; i < 500000; i++)  
  25.                 {  
  26.                     Person model = new Person();  
  27.                     model.FirstName = "Jeff";  
  28.                     model.LastName = "Wong";  
  29.                     model.Weight = 70;  
  30.                     model.Height = 180;  
  31.                     listModels.Add(model);  
  32.                 }  
  33.  
  34.                 Response.Write("Test Beginning......<br/>");  
  35.  
  36.                 int id = ServiceFactory.CreatePersonService().Add(sqlInsert);  
  37.                 Response.Write(string.Format("<br/>Insert and return id:{0}", id));  
  38.  
  39.                 bool flag = ServiceFactory.CreatePersonService().BatchInsert(listModels);  
  40.                 Response.Write(string.Format("<br/> Batch Insert {0}", flag ? "succeed" : "failed"));  
  41.  
  42.                 IList<Person> listPersons = ServiceFactory.CreatePersonService().GetPersons(sqlSelect);  
  43.                 Response.Write(string.Format("<br/>Select pesons and return persons:{0}", listPersons.Count));  
  44.  
  45.                 IDictionary<int, Person> dictPersons = ServiceFactory.CreatePersonService().GetDictPersons(sqlSelect);  
  46.                 Response.Write(string.Format("<br/>Select pesons and return dictionary persons:{0}", dictPersons.Count));  
  47.  
  48.                 DataTable dt = ServiceFactory.CreatePersonService().GetPersonTable(sqlSelect);  
  49.                 Response.Write(string.Format("<br/>Select pesons and return persons:{0}", dt.Rows.Count));  
  50.  
  51.                 DataSet ds = ServiceFactory.CreatePersonService().GetPersonDataSet(sqlSelect);  
  52.                 Response.Write(string.Format("<br/>Select pesons and return persons:{0}", ds.Tables[0].Rows.Count));  
  53.  
  54.                 int affectNum = ServiceFactory.CreatePersonService().Modify(sqlUpdate);  
  55.                 Response.Write(string.Format("<br/>Update and affect rows :{0}", affectNum));  
  56.  
  57.                 affectNum = 0;  
  58.                 affectNum = ServiceFactory.CreatePersonService().Remove(sqlDelete);  
  59.                 Response.Write(string.Format("<br/>Delete and affect rows :{0}", affectNum));  
  60.  
  61.                 Response.Write("<br/><br/>Test End.");  
  62.             }  
  63.         }  
  64.     }  

这个就不用多说了吧,表现层写SQL语句调用写好的服务就行了。比较不舒服的地方就是SQL语句不得不写在类里面,如果自动生成或者独立放在xml下实现可配置的形式那就更好了,当然sql语句不是我们讨论的重点,您有好的方法可以自己扩展实现更人性化的功能,减少书写SQLl语句的工作。

七、最后,对demo工程文件结构进行简单说明。 1、数据持久化层AdoNetDataAccess.Core 2、SqlMapper层AdoNetDataAccess.Mapper(引用AdoNetDataAccess.Core) 3、具体数据操作使用层AdoNetDataAccess.Dal(引用AdoNetDataAccess.Mapper) 4、表现层AdoNetDataAccessWebApp(引用AdoNetDataAccess.Dal) 可以看出,工程里的文件结构还是很清晰的,需要学习的童鞋不妨下载使用试试看吧

相关demo:http://files.cnblogs.com/wjfluisfigo/AdoNetDataAccessOrm.rar

原文标题:ado.net快速上手实践篇(二)

链接:http://www.cnblogs.com/wjfluisfigo/archive/2010/05/23/1742034.html

【编辑推荐】

  1. 详细述说ADO超时相关问题介绍
  2. 漫谈ADO.NET连接池相关注意问题说明
  3. 如何更好的进行ADO.NET连接池连接
  4. 剖析ADO.NET连接池优缺点
  5. 谈谈ADO.NET数据库连接池创建和分配
责任编辑:彭凡 来源: 博客园
相关推荐

2009-11-03 14:46:47

ADO.NET数据库

2009-11-11 14:27:32

ADO.NET函数

2009-10-29 13:34:01

ADO.NET对象

2009-11-13 09:45:54

ADO.NET程序集

2009-11-11 10:27:22

ADO.NET入门

2009-12-24 09:26:01

ADO.Net Tea

2009-12-21 15:58:19

ADO.NET集合

2009-11-04 16:55:16

ADO.NET Dat

2009-11-11 11:08:03

ADO.NET存储过程

2009-11-12 15:38:18

ADO.NET数据平台

2009-10-29 11:08:20

ADO.NET Dat

2009-11-04 10:35:42

ADO.NET Con

2009-12-28 15:11:36

ADO.NET专家

2009-11-12 09:36:32

ADO.NET Sql

2009-12-23 16:00:50

ADO.NET Ent

2009-11-13 09:24:17

2009-11-11 14:58:15

ADO.NET好处

2009-11-03 16:37:10

2009-11-11 16:37:50

ADO.NET新增特性

2009-09-14 13:37:25

LINQ ADO.NE
点赞
收藏

51CTO技术栈公众号