zoukankan      html  css  js  c++  java
  • [转]数据访问组件SqlHelper

    数据访问组件SqlHelper

    数据访问组件是一组通用的访问数据库的代码,在所有项目中都可以用,一般不需要修改。本节使用的是Microsoft提供的数据访问助手,其封装很严密,且应用简单。

    首先要先添加一个类,并命名为SqlHelper,系统会提示是否将类放在App_Code文件夹中。此时一定要选择“是”,因为放在此文件夹下,系统会自动进行编译,程序员就可以直接使用,无需另外编译了。

    SqlHelper的功能

    SqlHelper的目的是从数据库获得信息或将信息保存到数据库。本实例的SqlHelper主要功能如下。

    (1)执行不返回数据的T-Sql命令。例如修改会员卡信息、添加会员资料等。

    (2)返回一个字段的T-Sql命令。例如获取会员卡类型的积分规则。

    (3)返回一组数据。例如获取会员资料、获取所有会员卡类型等。

    (4)缓存参数列表。在执行一条语句时,可能有多个参数,为了提高速度,将参数缓存。

    (5)读取缓存的参数。

    下面用图表的方式描述SqlHelper类的功能,如图7-16所示。

    7-16  SqlHelper功能图

    代码清单

    在SqlHelper类中添加数据库处理,代码如清单7-4所示。

    代码清单7-4  SqlHelper代码

    //编号1

    using System;

    using System.Data;

    using System.Configuration;

    using System.Web;

    using System.Web.Security;

    using System.Collections;

    using System.Data.SqlClient;

    //编号2

    /// <summary>

    /// 数据库的通用访问代码

    /// 此类为抽象类,不允许实例化,在应用时直接调用即可

    /// </summary>

    public abstract class SqlHelper

    {

        //获取数据库连接字符串,其属于静态变量且只读,项目中所有文档可以直接使用,但不能修改

        //编号13

        public static readonly string ConnectionStringLocalTransaction =

        ConfigurationManager.ConnectionStrings["connstring"].ConnectionString;

        // 哈希表用来存储缓存的参数信息,哈希表可以存储任意类型的参数

        //编号8

        private static Hashtable parmCache = Hashtable.Synchronized(new

        Hashtable());//编号9

        /// <summary>

        ///执行一个不需要返回值的SqlCommand命令,通过指定专用的连接字符串。

        /// 使用参数数组形式提供参数列表

        /// </summary>

        /// <remarks>

        /// 使用示例:

        ///  int result = ExecuteNonQuery(connString, CommandType.StoredProcedure,
             ///  "PublishOrders", new SqlParameter("@prodid", 24));

        /// </remarks>

        /// <param name="connectionString">一个有效的数据库连接字符串</param>

        /// <param name="commandType">SqlCommand命令类型 (存储过程, T-SQL语句,等等。)

        /// </param>

        /// <param name="commandText">存储过程的名字或者 T-SQL 语句</param>

        /// <param name="commandParameters">以数组形式提供SqlCommand命令中用到的参数列表

        /// </param>

        /// <returns>返回一个数值表示此SqlCommand命令执行后影响的行数</returns>

        //编号3

        public static int ExecuteNonQuery(string connectionString, CommandType cmdType,

        string cmdText, params SqlParameter[] commandParameters)

        {

            SqlCommand cmd = new SqlCommand();

            //编号4

            using (SqlConnection conn = new SqlConnection(connectionString))

            {

                //通过PrePareCommand方法将参数逐个加入到SqlCommand的参数集合中

                PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);

                int val = cmd.ExecuteNonQuery();

                //清空SqlCommand中的参数列表

                cmd.Parameters.Clear();

                //编号14

                return val;

            }

        }

       

        /// <summary>

        ///执行一条不返回结果的SqlCommand,通过一个已经存在的数据库连接

        /// 使用参数数组提供参数

        /// </summary>

        /// <remarks>

        /// 使用示例: 

        /// int result = ExecuteNonQuery(conn, CommandType.StoredProcedure,

        /// "PublishOrders", new SqlParameter("@prodid", 24));

        /// </remarks>

        /// <param name="conn">一个现有的数据库连接</param>

        /// <param name="commandType">SqlCommand命令类型 (存储过程, T-SQL语句,等等。)

        /// </param>

        /// <param name="commandText">存储过程的名字或者 T-SQL 语句</param>

        /// <param name="commandParameters">以数组形式提供SqlCommand命令中用到的参数列表

        /// </param>

        /// <returns>返回一个数值表示此SqlCommand命令执行后影响的行数</returns>

        //编号5

        public static int ExecuteNonQuery(SqlConnection connection, CommandType cmdType, string cmdText, params SqlParameter[] commandParameters)

        {

            SqlCommand cmd = new SqlCommand();

            PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters);

            int val = cmd.ExecuteNonQuery();

            cmd.Parameters.Clear();

            return val;

        }

        /// <summary>

        /// 执行一条不返回结果的SqlCommand,通过一个已经存在的数据库事物处理

        /// 使用参数数组提供参数

        /// </summary>

        /// <remarks>

        /// 使用示例:

        ///  int result = ExecuteNonQuery(trans, CommandType.StoredProcedure,

        /// "PublishOrders", new SqlParameter("@prodid", 24));

        /// </remarks>

        /// <param name="trans">一个存在的 sql 事物处理</param>

        /// <param name="commandType">SqlCommand命令类型 (存储过程, T-SQL语句,等等。)

        /// </param>

        /// <param name="commandText">存储过程的名字或者 T-SQL 语句</param>

        /// <param name="commandParameters">以数组形式提供SqlCommand命令中用到的参数列表

        /// </param>

        /// <returns>返回一个数值表示此SqlCommand命令执行后影响的行数</returns>

        //编号12

        public static int ExecuteNonQuery(SqlTransaction trans, CommandType cmdType,

    string cmdText, params SqlParameter[] commandParameters)

        {

            SqlCommand cmd = new SqlCommand();

            PrepareCommand(cmd, trans.Connection, trans, cmdType, cmdText, commandParameters);

            int val = cmd.ExecuteNonQuery();

            cmd.Parameters.Clear();

            return val;

        }

        /// <summary>

        /// 执行一条返回结果集的SqlCommand命令,通过专用的连接字符串。

        /// 使用参数数组提供参数

        /// </summary>

        /// <remarks>

        /// 使用示例: 

        ///  SqlDataReader r = ExecuteReader(connString, CommandType.StoredProcedure,

        /// "PublishOrders", new SqlParameter("@prodid", 24));

        /// </remarks>

        /// <param name="connectionString">一个有效的数据库连接字符串</param>

        /// <param name="commandType">SqlCommand命令类型 (存储过程, T-SQL语句,等等。)

        /// </param>

        /// <param name="commandText">存储过程的名字或者 T-SQL 语句</param>

        /// <param name="commandParameters">以数组形式提供SqlCommand命令中用到的参数列表

        /// </param>

        /// <returns>返回一个包含结果的SqlDataReader</returns>

        public static SqlDataReader ExecuteReader(string connectionString, CommandType

    cmdType, string cmdText, params SqlParameter[] commandParameters)

        {

            SqlCommand cmd = new SqlCommand();

            SqlConnection conn = new SqlConnection(connectionString);

            // 在这里使用try/catch处理是因为如果方法出现异常,则SqlDataReader就不存在,

            //CommandBehavior.CloseConnection的语句就不会执行,触发的异常由catch捕获。

            //关闭数据库连接,并通过throw再次引发捕捉到的异常。 

          try

            {

                PrepareCommand(cmd, conn, null, cmdType, cmdText, commandParameters);

                SqlDataReader rdr = cmd.ExecuteReader(CommandBehavior.CloseConnection);

                cmd.Parameters.Clear();

                return rdr;

            }

            catch

            {

                conn.Close();

                throw;  //编号7

            }

        }

        /// <summary>

        /// 执行一条返回第一条记录第一列的SqlCommand命令,通过专用的连接字符串。

        /// 使用参数数组提供参数

        /// </summary>

        /// <remarks>

        /// 使用示例: 

        ///  Object obj = ExecuteScalar(connString, CommandType.StoredProcedure,

        /// "PublishOrders", new SqlParameter("@prodid", 24));

        /// </remarks>

        /// <param name="connectionString">一个有效的数据库连接字符串</param>

        /// <param name="commandType">SqlCommand命令类型 (存储过程, T-SQL语句,等等。)

        /// </param>

        /// <param name="commandText">存储过程的名字或者 T-SQL 语句</param>

        /// <param name="commandParameters">以数组形式提供SqlCommand命令中用到的参数列表

        /// </param>

        /// <returns>返回一个object类型的数据,可以通过 Convert.To{Type}方法转换类型</returns>

        public static object ExecuteScalar(string connectionString, CommandType

    cmdType, string cmdText, params SqlParameter[] commandParameters)

        {

            SqlCommand cmd = new SqlCommand();

            using (SqlConnection connection = new SqlConnection(connectionString))

            {

                PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters);

                object val = cmd.ExecuteScalar();

                cmd.Parameters.Clear();

                return val;

            }

        }

        /// <summary>

        /// 执行一条返回第一条记录第一列的SqlCommand命令,通过已经存在的数据库连接。

        /// 使用参数数组提供参数

        /// </summary>

        /// <remarks>

        /// 使用示例:

        ///  Object obj = ExecuteScalar(connString, CommandType.StoredProcedure,

        /// "PublishOrders", new SqlParameter("@prodid", 24));

        /// </remarks>

        /// <param name="conn">一个已经存在的数据库连接</param>

        /// <param name="commandType">SqlCommand命令类型 (存储过程, T-SQL语句,等等。)

        /// </param>

        /// <param name="commandText">存储过程的名字或者 T-SQL 语句</param>

        /// <param name="commandParameters">以数组形式提供SqlCommand命令中用到的参数列表

        /// </param>

        /// <returns>返回一个object类型的数据,可以通过 Convert.To{Type}方法转换类型

        /// </returns>

        public static object ExecuteScalar(SqlConnection connection, CommandType

    cmdType, string cmdText, params SqlParameter[] commandParameters)

        {

            SqlCommand cmd = new SqlCommand();

            PrepareCommand(cmd, connection, null, cmdType, cmdText, commandParameters);

            object val = cmd.ExecuteScalar();

            cmd.Parameters.Clear();

            return val;

        }

        /// <summary>

        /// 缓存参数数组

        /// </summary>

        /// <param name="cacheKey">参数缓存的键值</param>

        /// <param name="cmdParms">被缓存的参数列表</param>

        public static void CacheParameters(string cacheKey, params SqlParameter[]

    commandParameters)

        {

        //编号10

            parmCache[cacheKey] = commandParameters;

        }

        /// <summary>

        /// 获取被缓存的参数

        /// </summary>

        /// <param name="cacheKey">用于查找参数的KEY</param>

        /// <returns>返回缓存的参数数组</returns>

        public static SqlParameter[] GetCachedParameters(string cacheKey)

        {

            SqlParameter[] cachedParms = (SqlParameter[])parmCache[cacheKey];

            if (cachedParms == null)

                 return null;

            //新建一个参数的克隆列表

            SqlParameter[] clonedParms = new SqlParameter[cachedParms.Length];

            //通过循环为克隆参数列表赋值

            for (int i = 0, j = cachedParms.Length; i < j; i++)

                //使用clone方法复制参数列表中的参数

                //编号11

                clonedParms[i] = (SqlParameter)((ICloneable)cachedParms[i]).Clone();

            return clonedParms;

        }

        /// <summary>

        /// 为执行命令准备参数

        /// </summary>

        /// <param name="cmd">SqlCommand 命令</param>

        /// <param name="conn">已经存在的数据库连接</param>

        /// <param name="trans">数据库事物处理</param>

        /// <param name="cmdType">SqlCommand命令类型 (存储过程,T-SQL语句,等等。) </param>

        /// <param name="cmdText">Command textT-SQL语句例如 Select * from

        /// Products</param>

        /// <param name="cmdParms">返回带参数的命令</param>

        //编号6

        private static void PrepareCommand(SqlCommand cmd, SqlConnection conn,

    SqlTransaction trans, CommandType cmdType, string cmdText, SqlParameter[]
             cmdParms)

        {

            //判断数据库连接状态

            if (conn.State != ConnectionState.Open)

                conn.Open();

            cmd.Connection = conn;

            cmd.CommandText = cmdText;

            //判断是否需要事物处理

            if (trans != null)

                cmd.Transaction = trans;

            cmd.CommandType = cmdType;

            if (cmdParms != null)

            {

                foreach (SqlParameter parm in cmdParms)

                    cmd.Parameters.Add(parm);

            }

        }

    }

    代码技术分析

    代码清单7-4是一个比较完整的数据访问组件,下面分析这些代码的具体实现。

    (1)Using关键字:见代码编号1。Using处理对命名空间的引用。通常,如果系统提示找不到某个类,一定要仔细检查是否引用了这个类的命名空间。在C# 2.0中Using还可以实现命名空间的别名,例如:Using sc =System.Collections。别名就是用来简化命名空间的,别名的使用语句是:sc::ArrayList list=new sc::Arraylist( )。

    (2)注释:见代码编号2。在方法上面一行如果输入“///”,系统会自动将此方法的注释架构搭建好,主要包括Summary和param name。如果方法有返回值,还包括returns;如果需要特殊说明可以使用remarks标志。根据这个结构,可以很容易地描述清楚整个方法的组成及使用方法。在注释中使用“///”,将来在代码调用时,会出现提示,提示的内容就是所添加的注释。

    (3)CommandType的使用:见代码编号3。SQL Server数据处理的两种方法:存储过程和T-SQL语句。每条执行语句都有个参数CommandType,这是个枚举类型,有3个选项:StoredProcedure、TableDirect和Text。它们分别表示存储过程、表和T-SQL语句。如果CommandType参数选择StoredProcedure,则cmdText参数就是存储过程的名字;如果CommandType是Text,则cmdText是SQL语句;如果CommandType是TableDirect,则cmdText是表名称。

    (4)Using语句:见代码编号4。在Using语句中,用“{}”定义一个范围,在语句完成时释放语句内使用的资源。Using语句通常用在获取数据的方法中,语句的范围是从打开数据库连接开始,到所有使用连接的资源都运行完毕后终止。Using语句可以与多个对象一起使用。使用Using语句的对象必须继承IDispose接口。此接口实现了Dispose方法,该方法才是释放对象资源的执行者。

    (5)参数数组:见代码编号5。在C#中不允许使用可选参数,所以参数通常由不指定大小的数组来实现。数组中参数的添加由PrepareCommand方法完成。

    (6)SQL事务处理:见代码编号6。事务是指一组相关联的操作。在事务处理时,通常锁住相关的表,等事务处理完成后才解锁,这样保证了数据的完整性。事务一般包括3个方法:开始事务、执行事务和事务回滚(RollBack)。如果事务中的一条语句出现问题,则事务回滚,其他语句的执行也被取消。

    (7)throw:见代码编号7。再次引发捕获的异常,目的是向文本中添加异常处理信息。如果要引发异常,throw和catch一定要搭配使用,如果catch有参数,则throw也要带参数,相反亦然。

    (8)哈希表:见代码编号8。表示键/值(key/value)对的组合。通过键值的映射来访问哈希代码。.NET中的哈希表是System.Collections命名空间提供的一个容器,英文名称为HashTable,通过key来实现快速查找,key区分大小写。value存储key对应的值,通常表现为object类型,当取值时要进行相应的类型转换。

    (9)哈希表的同步包装:见代码编号9。private static Hashtable parmCache = Hashtable. Synchronized(new Hashtable( ))这条语句实现了哈希表的同步包装,包装是基于线程安全的。此处的哈希表是static类型的静态变量,既然是static,就是一次定义,全局使用。所有的参数都使用这个哈希表,那如何保证其他人在修改的时候不影响自己的读取呢?以前可以使用lock的方法先锁定表,不允许他人修改,读取完毕后再解锁。现在.NET提供了HashTable的Synchronized方法,实现同样的功能,不需要手动加锁,直接由系统框架完成。

    (10)缓存参数列表:见代码编号10。缓存参数列表就是将参数信息保存在已经定义的静态HashTable中。因为HashTable是静态的,一旦定义,就分配了内存地址,在项目中随时都可以使用,起到了缓存数据的作用。

    (11)clone:克隆。见代码编号11。在.NET中,几乎所有继承Collections类的集合都具有clone的方法。在获取缓存参数的方法中有下面这句代码:clonedParms[i] = (SqlParameter) ((ICloneable)cachedParms[i]).Clone( )。因为所有的参数都保存在一个HashTable中,表中保存的只是参数的名字,而参数的内容则是由不同的调用给予不同的值。为了正确反映调用者的值,必须克隆出一个参数列表,由调用者根据功能赋予对应的值。

    (12)方法重载:见代码编号12。定义了两个或多个具有相同名称但参数不同的方法。在SqlHelper中,ExcuteNonQuery被重载了4次,通过代码中的注释可以很清楚地看出参数列表的不同。在实际应用中,根据功能环境调用相应的方法。

    (13)ConfigurationManager:见代码编号13。是ASP.NET 2.0中新加的一个类,主要对Web.config文件进行管理。可以轻松获取在Web.config文件中定义的配置,通常用来获取数据库连接字符串和个性化配置信息。本例在Web.config中添加了下面这行数据库连接字符串配置。

    <connectionStrings  >

      <add name="connstring" connectionString ="server=.;database=membercard; uid=sa; pwd="/>

    </connectionStrings>

    (14)ExcuteNonQuery方法的返回值:见代码编号14。在SqlCommand的方法中,ExcuteNonQuery用来执行插入、更新或删除等操作。程序并不要求有任何返回值,但在SqlHelper中定义此方法时返回了一个数值型数据。该数据用来表示执行当前语句后数据库中被影响的行数。虽然在此定义了返回值,但在程序的调用中,可以不用返回值,直接执行方法。例如:SqlHelper. ExcuteNonQuery( )就是正确的,不一定非要写成 int val= SqlHelper. ExcuteNonQuery( )。如果程序中需要的不是int值,还可以进行转换。

     

  • 相关阅读:
    Atitit. visual studio vs2003 vs2005 vs2008  VS2010 vs2012 vs2015新特性 新功能.doc
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit. C#.net clr 2.0  4.0新特性
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit.通过null 参数 反射  动态反推方法调用
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit..net clr il指令集 以及指令分类  与指令详细说明
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.变量的定义 获取 储存 物理结构 基本类型简化 隐式转换 类型推导 与底层原理 attilaxDSL
    Atitit.跨语言反射api 兼容性提升与增强 java c#。Net  php  js
  • 原文地址:https://www.cnblogs.com/cxy521/p/1022791.html
Copyright © 2011-2022 走看看