打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
ado.net快速上手实践篇(一)-ASP.NET应用-www.knowsky.com
前言:这两天重温经典,对ado.net的东西稍微深入的了解了一下,顺便写点代码练练手,全当是复习笔记吧。
一、简单说说ado.net的5大常用对象
既然说ado.net,当然不能免俗地要提到5大常用对象。本文不会对ado.net的5大对象和它们的关系进行过多阐释,不过我们应该对下面这张图的结构有个了解:

关于上图图示中的5大对象,经常做以数据为驱动的mis系统的童鞋应该不会陌生。本文一笔带过。下面我们一步一步实现以ado.net为核心的数据访问程序。
【注意:下面的示例代码和demo是楼猪本周六和周日两天时间实现的,未经详细测试,可能有重大bug,下载学习使用的童鞋务必注意】
二、数据访问持久化层
1、IDbOperation接口

代码
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
namespace AdoNetDataaccess.Core.Contract
{
    public interface IDbOperation
    {
        DbCommand CreateDbCommd(DbConnection sqlConn, DbTransaction transaction, string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        DbParameter CreateDbPRameter(string paramName, object paramValue);
        DbDataReader ExecuteReader(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        DataTable FillDataTable(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        DataSet FillDataSet(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        object ExecuteScalar(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        int ExecuteNonQuery(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        /// <summary>
        /// 批量插入
        /// </summary>
        /// <param name="tableName">表名称</param>
        /// <param name="dt">组装好的要批量导入的datatable</param>
        /// <returns></returns>
        bool ExecuteBatchInsert(string tableName, int batchSize, int copyTimeout, DataTable dt);
        void OpenConnection();
        void CloseConnection();
    }
}

上面的接口包括增删改查,批量插入以及数据库连接对象的连接和关闭等常用操作,您可以根据命名和参数轻松理解函数的含义。根据楼猪的开发经验,对于平时的数据库操作,上述方法差不多够用了。当然您也可以按照自己需要,重写组织添加其他函数。
2、针对一种数据源的数据操作实现
底层的数据操作接口定义好后,就要针对一种数据源,具体实现上述的数据操作。这里楼猪选择了Sql Server。我们也可以实现其他数据源的数据访问操作,按照配置,利用抽象工厂动态反射选择是哪一种数据源的实现。这里按下不表,有心的童鞋自己可以动手一试。下面是具体的实现:

代码
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
using System.Transactions;
namespace AdoNetDataAccess.Core.Implement
{
    using AdoNetDataAccess.Core.Contract;
    public class SqlServer : IDbOperation, IDisposable
    {
        private int cmdTimeOut = 60;
        private DbConnection sqlConn = null;
        private DbCommand cmd = null;
        private SqlServer()
        {
        }
        public SqlServer(string sqlConStr)
        {
            sqlConn = new SqlConnection(sqlConStr);
            cmdTimeOut = sqlConn.ConnectionTimeout;
        }
        public SqlServer(string sqlConStr, int timeOut)
        {
            sqlConn = new SqlConnection(sqlConStr);
            if (timeOut < 0)
            {
                timeOut = sqlConn.ConnectionTimeout;
            }
            cmdTimeOut = timeOut;
        }
        #region contract method
        public DbCommand CreateDbCommd(DbConnection sqlConn, DbTransaction transaction, string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            DbCommand cmd = new SqlCommand();
            cmd.Connection = sqlConn;
            cmd.CommandText = sqlStr;
            cmd.CommandType = cmdType;
            if (transaction != null)
            {
                cmd.Transaction = transaction;
            }
            if (listParams != null && listParams.Count > 0)
            {
                cmd.Parameters.AddRange(listParams.ToArray());
            }
            cmd.CommandTimeout = cmdTimeOut;
            OpenConnection();
            return cmd;
        }
        public DbParameter CreateDbPrameter(string paramName, object paramValue)
        {
            SqlParameter sp = new SqlParameter(paramName, paramValue);
            return sp;
        }
        public DbDataReader ExecuteReader(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            DbDataReader rdr = null;
            try
            {
                OpenConnection();
                cmd = CreateDbCommd(sqlConn, null, sqlStr, cmdType, listParams);
                rdr = cmd.ExecuteReader();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return rdr;
        }
        public DataTable FillDataTable(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            OpenConnection();
            DbTransaction trans = sqlConn.BeginTransaction();
            DbCommand cmd = CreateDbCommd(sqlConn, trans, sqlStr, cmdType, listParams);
            SqlDataAdapter sqlDataAdpter = new SqlDataAdapter(cmd as SqlCommand);
            DataTable dt = new DataTable();
            try
            {
                sqlDataAdpter.Fill(dt);
                trans.Commit();
            }
            catch (Exception e)
            {
                trans.Rollback();
                throw new Exception("执行数据库操作失败, sql: " + sqlStr, e);
            }
            finally
            {
                sqlDataAdpter.Dispose();
                cmd.Dispose();
                trans.Dispose();
                CloseConnection();
            }
            return dt;
        }
        public DataSet FillDataSet(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            OpenConnection();
            DbTransaction trans = sqlConn.BeginTransaction();
            DbCommand cmd = CreateDbCommd(sqlConn, trans, sqlStr, cmdType, listParams);
            SqlDataAdapter sqlDataAdpter = new SqlDataAdapter(cmd as SqlCommand);
            DataSet ds = new DataSet();
            try
            {
                sqlDataAdpter.Fill(ds);
                trans.Commit();
            }
            catch (Exception e)
            {
                trans.Rollback();
                throw new Exception("执行数据库操作失败, sql: " + sqlStr, e);
            }
            finally
            {
                sqlDataAdpter.Dispose();
                cmd.Dispose();
                trans.Dispose();
                CloseConnection();
            }
            return ds;
        }
        public object ExecuteScalar(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            object result = null;
            OpenConnection();
            DbTransaction trans = sqlConn.BeginTransaction();
            try
            {
                cmd = CreateDbCommd(sqlConn, trans, sqlStr, cmdType, listParams);
                result = cmd.ExecuteScalar();
                trans.Commit();
            }
            catch (Exception e)
            {
                trans.Rollback();
                throw new Exception("执行数据库操作失败, sql: " + sqlStr, e);
            }
            finally
            {
                trans.Dispose();
                CloseConnection();
            }
            return result;
        }
        public int ExecuteNonQuery(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            int result = -1;
            OpenConnection();
            DbTransaction trans = sqlConn.BeginTransaction();
            try
            {
                cmd = CreateDbCommd(sqlConn, trans, sqlStr, cmdType, listParams);
                result = cmd.ExecuteNonQuery();
                trans.Commit();
            }
            catch (Exception e)
            {
                trans.Rollback();
                throw new Exception("执行数据库操作失败, sql: " + sqlStr, e);
            }
            finally
            {
                trans.Dispose();
                CloseConnection();
            }
            return result;
        }
        /// <summary>
        /// 批量插入
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="batchSize"></param>
        /// <param name="copyTimeout"></param>
        /// <param name="dt"></param>
        /// <returns></returns>
        public bool ExecuteBatchInsert(string tableName, int batchSize, int copyTimeout, DataTable dt)
        {
            bool flag = false;
            try
            {
                using (TransactionScope scope = new TransactionScope())
                {
                    OpenConnection();
                    using (SqlBulkCopy sbc = new SqlBulkCopy(sqlConn as SqlConnection))
                    {
                        //服务器上目标表的名称
                        sbc.DestinationTableName = tableName;
                        sbc.BatchSize = batchSize;
                        sbc.BulkCopyTimeout = copyTimeout;
                        for (int i = 0; i < dt.Columns.Count; i++)
                        {
                            //列映射定义数据源中的列和目标表中的列之间的关系
                            sbc.ColumnMappings.Add(dt.Columns[i].ColumnName, dt.Columns[i].ColumnName);
                        }
                        sbc.WriteToServer(dt);
                        flag = true;
                        scope.Complete();//有效的事务
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return flag;
        }
        public void OpenConnection()
        {
            if (sqlConn.State == ConnectionState.Broken || sqlConn.State == ConnectionState.Closed)
                sqlConn.Open();
        }
        public void CloseConnection()
        {
            sqlConn.Close();
        }
        #endregion
        #region dispose method
        /// <summary>
        /// dispose接口方法
        /// </summary>
        public void Dispose()
        {
        }
        #endregion
    }
}
到这里,我们实现了SqlServer类里的方法,对Ms SqlServer数据库我们就已经可以进行简单的基础的CRUD操作了。
三、简单直观的对象实体转换
在第二步中,我们已经实现了简单的数据CRUD操作。根据楼猪使用ORM的经验和习惯,我们也应该对一些查询结果进行转换,因为以类的组织方式比直接呈现ado.net对象更容易让人接受,效率高低反在其次。下面利用常见的反射原理,简单实现一个对象实体转换器ModelConverter类:

代码
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Reflection;
using System.Threading;
namespace AdoNetDataAccess.Core.Obj2Model
{
    using AdoNetDataAccess.Core.Contract;
    public sealed class ModelConverter
    {
        private static readonly object objSync = new object();
        #region query for list
        /// <summary>
        /// 查询数据表项并转换为对应实体
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="objType"></param>
        /// <param name="rdr"></param>
        /// <returns></returns>
        public static IList<T> QueryForList<T>(string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType, IDbOperation dbOperation)
            where T : class, new()
        {
            IDataReader rdr = dbOperation.ExecuteReader(sqlStr, cmdType, listParams);
            IList<T> listModels = new List<T>();
            try
            {
                Monitor.Enter(objSync);
                Hashtable ht = CreateHashColumnName(rdr);
                while (rdr.Read())
                {
                    Object obj = Activator.CreateInstance(objType);
                    PropertyInfo[] properties = objType.GetProperties();
                    foreach (PropertyInfo propInfo in properties)
                    {
                        string columnName = propInfo.Name.ToUpper();
                        if (ht.ContainsKey(columnName) == false)
                        {
                            continue;
                        }
                        int index = rdr.GetOrdinal(propInfo.Name);
                        object columnValue = rdr.GetValue(index);
                        if (columnValue != System.DBNull.Value)
                        {
                            SetValue(propInfo, obj, columnValue);
                        }
                    }
                    T model = default(T);
                    model = obj as T;
                    listModels.Add(model);
                }
            }
            finally
            {
                rdr.Close();
                rdr.Dispose();
                Monitor.Exit(objSync);
            }
            return listModels;
        }
        #endregion
        #region query for dictionary
        /// <summary>
        /// 查询数据表项并转换为对应实体
        /// </summary>
        /// <typeparam name="K"></typeparam>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">字典对应key列名</param>
        /// <param name="objType"></param>
        /// <param name="rdr"></param>
        /// <returns></returns>
        public static IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType, IDbOperation dbOperation)
            where T : class, new()
        {
            IDataReader rdr = dbOperation.ExecuteReader(sqlStr, cmdType, listParams);
            IDictionary<K, T> dictModels = new Dictionary<K, T>();
            try
            {
                Monitor.Enter(objSync);
                Hashtable ht = CreateHashColumnName(rdr);
                while (rdr.Read())
                {
                    Object obj = Activator.CreateInstance(objType);
                    PropertyInfo[] properties = objType.GetProperties();
                    object dictKey = null;
                    foreach (PropertyInfo propInfo in properties)
                    {
                        string columnName = propInfo.Name.ToUpper();
                        if (ht.ContainsKey(columnName) == false)
                        {
                            continue;
                        }
                        int index = rdr.GetOrdinal(propInfo.Name);
                        object columnValue = rdr.GetValue(index);
                        if (columnValue != System.DBNull.Value)
                        {
                            SetValue(propInfo, obj, columnValue);
                            if (string.Compare(columnName, key.ToUpper()) == 0)
                            {
                                dictKey = columnValue;
                            }
                        }
                    }
                    T model = default(T);
                    model = obj as T;
                    K objKey = (K)dictKey;
                    dictModels.Add(objKey, model);
                }
            }
            finally
            {
                rdr.Close();
                rdr.Dispose();
                Monitor.Exit(objSync);
            }
            return dictModels;
        }
        #endregion
        #region internal util
        private static Hashtable CreateHashColumnName(IDataReader rdr)
        {
            int len = rdr.FieldCount;
            Hashtable ht = new Hashtable(len);
            for (int i = 0; i < len; i++)
            {
                string columnName = rdr.GetName(i).ToUpper(); //不区分大小写
                string columnRealName = rdr.GetName(i);
                if (ht.ContainsKey(columnName) == false)
                {
                    ht.Add(columnName, columnRealName);
                }
            }
            return ht;
        }
        private static void SetValue(PropertyInfo propInfo, Object obj, object objValue)
        {
            try
            {
                propInfo.SetValue(obj, objValue, null);
            }
            catch
            {
                object realValue = null;
                try
                {
                    realValue = Convert.ChangeType(objValue, propInfo.PropertyType);
                    propInfo.SetValue(obj, realValue, null);
                }
                catch (Exception ex)
                {
                    string err = ex.Message;
                    //throw ex; //在数据库数据有不符合规范的情况下应该及时抛出异常
                }
            }
        }
        #endregion
    }
}
 
到这里,简单的数据访问持久化层就实现了。下面模仿楼猪使用的IBatis.net,写个伪SqlMapper,改善一下调用形式,丰富一下调用方法,让方法辨识度更高。
四、实现伪SqlMapper
1、BaseMapper类

代码
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.SqlClient;
namespace AdoNetDataAccess.Mapper
{
    using AdoNetDataAccess.Core.Contract;
    public abstract class BaseMapper
    {
        public IDbOperation CurrentDbOperation;
        #region query for list
        public abstract IList<T> QueryForList<T>(string sqlStr)
  where T : class, new();
        public abstract IList<T> QueryForList<T>(string sqlStr, Type objType)
where T : class, new();
        public abstract IList<T> QueryForList<T>(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
       where T : class, new();
        public abstract IList<T> QueryForList<T>(string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType)
       where T : class, new();

        #endregion
        #region query for dictionary
        public abstract IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr)
            where T : class, new();
        public abstract IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, Type objType)
    where T : class, new();
        public abstract IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, CommandType cmdType, Type objType)
            where T : class, new();
        public abstract IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType)
                    where T : class, new();
        #endregion
        #region dataset datatable
        public abstract DataTable FillDataTable(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        public abstract DataSet FillDataSet(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        #endregion
        #region ExecuteScalar
        public abstract object ExecuteScalar(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        #endregion
        #region insert
        public abstract int Insert(string sqlStr);
        public abstract int Insert(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        public abstract bool BatchInsert(string tableName, int batchSize, int copyTimeout, DataTable dt);
        #endregion
        #region delete
        public abstract int Delete(string sqlStr);
        public abstract int Delete(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        #endregion
        #region update
        public abstract int Update(string sqlStr);
        public abstract int Update(string sqlStr, CommandType cmdType, List<DbParameter> listParams);
        #endregion
    }
}
上面代码中的方法您是不是很熟悉呢? 呵呵,使用IBatis.net 的童鞋应该会和楼猪产生更多的共鸣。
2、SqlMapper类
代码
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
namespace AdoNetDataAccess.Mapper
{
    using AdoNetDataAccess.Core.Contract;
    using AdoNetDataAccess.Core.Obj2Model;
    public class SqlMapper : BaseMapper
    {
        private SqlMapper()
        {
        }
        public SqlMapper(IDbOperation dbOperation)
        {
            this.CurrentDbOperation = dbOperation;
        }
        #region query for list
        public override IList<T> QueryForList<T>(string sqlStr)
        {
            return QueryForList<T>(sqlStr, CommandType.Text, null, typeof(T));
        }
        public override IList<T> QueryForList<T>(string sqlStr, Type objType)
        {
            return QueryForList<T>(sqlStr, CommandType.Text, null, objType);
        }
        public override IList<T> QueryForList<T>(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            return QueryForList<T>(sqlStr, cmdType, listParams, typeof(T));
        }
        public override IList<T> QueryForList<T>(string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType)
        {
            return ModelConverter.QueryForList<T>(sqlStr, cmdType, listParams, objType, this.CurrentDbOperation);
        }
        #endregion
        #region query for dictionary
        public override IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr)
        {
            return QueryForDictionary<K, T>(key, sqlStr, CommandType.Text, null, typeof(T));
        }
        public override IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, Type objType)
        {
            return QueryForDictionary<K, T>(key, sqlStr, CommandType.Text, null, objType);
        }
        public override IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, CommandType cmdType, Type objType)
        {
            return QueryForDictionary<K, T>(key, sqlStr, cmdType, null, objType);
        }
        public override IDictionary<K, T> QueryForDictionary<K, T>(string key, string sqlStr, CommandType cmdType, List<DbParameter> listParams, Type objType)
        {
            return ModelConverter.QueryForDictionary<K, T>(key, sqlStr, cmdType, listParams, objType, this.CurrentDbOperation);
        }
        #endregion
        #region dataset datatable
        public override DataTable FillDataTable(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            return this.CurrentDbOperation.FillDataTable(sqlStr, cmdType, listParams);
        }
        public override DataSet FillDataSet(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            return this.CurrentDbOperation.FillDataSet(sqlStr, cmdType, listParams);
        }
        #endregion
        #region ExecuteScalar
        public override object ExecuteScalar(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            return this.CurrentDbOperation.ExecuteScalar(sqlStr, cmdType, listParams);
        }
        #endregion
        #region insert
        public override int Insert(string sqlStr)
        {
            object obj = ExecuteScalar(sqlStr, CommandType.Text, null);
            int id = obj == null ? 0 : int.Parse(obj.ToString());
            return id;
        }
        public override int Insert(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            object obj = ExecuteScalar(sqlStr, cmdType, listParams);
            int id = obj == null ? 0 : int.Parse(obj.ToString());
            return id;
        }
        /// <summary>
        /// 批量插入
        /// </summary>
        /// <param name="tableName"></param>
        /// <param name="batchSize"></param>
        /// <param name="copyTimeout"></param>
        /// <param name="dt"></param>
        /// <returns></returns>
        public override bool BatchInsert(string tableName, int batchSize, int copyTimeout, DataTable dt)
        {
            return this.CurrentDbOperation.ExecuteBatchInsert(tableName, batchSize, copyTimeout, dt);
        }
        #endregion
        #region delete
        public override int Delete(string sqlStr)
        {
            return CommitSql(sqlStr, CommandType.Text, null);
        }
        public override int Delete(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            return CommitSql(sqlStr, cmdType, listParams);
        }
        #endregion
        #region update
        public override int Update(string sqlStr)
        {
            return CommitSql(sqlStr, CommandType.Text, null);
        }
        public override int Update(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            return CommitSql(sqlStr, cmdType, listParams);
        }
        #endregion
        #region commit and execute sql
        private int CommitSql(string sqlStr, CommandType cmdType, List<DbParameter> listParams)
        {
            return this.CurrentDbOperation.ExecuteNonQuery(sqlStr, cmdType, listParams);
        }
        #endregion
        #region  dbparameter
        public DbParameter CreateParameter(string paraName, object paramValue)
        {
            return this.CurrentDbOperation.CreateDbPrameter(paraName, paramValue);
        }
        public List<DbParameter> CreateParameterList(string[] paraNames, object[] paramValues)
        {
            List<DbParameter> listParams = new List<DbParameter>();
            try
            {
                if (paraNames.Length != paramValues.Length)
                {
                    throw new Exception("Param name and value is not equal.");
                }
                for (int i = 0; i < paraNames.Length; i++)
                {
                    DbParameter param = CreateParameter(paraNames[i], paramValues[i]);
                    listParams.Add(param);
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return listParams;
        }
        #endregion
    }
}
上面的方法丰富实现了CRUD的常见操作,其实主要还是调用了IDbOperation接口和方法。
未完,待续。
demo下载:demo
-
本文来自: 动态网站制作(www.knowsky.com) 详细出处参考:http://www.knowsky.com/544464.html
本文来自: 动态网站制作(www.knowsky.com) 详细出处参考:http://www.knowsky.com/544464.html
本文来自: 动态网站制作(www.knowsky.com) 详细出处参考:http://www.knowsky.com/544464.html
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
操作数据库的类DbHelper.cs
使用DBHelper
浅谈PetShop之使用存储过程与PLSQL批量处理(附案例)
批量插入数据, 将DataTable里的数据批量写入数据库的方法
Asp.net Access 数据访问通用类
Dbconn 连接问题
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服