SQLHelper很好地体现了抽象和封装的思想,为了避免每次连接数据库时都要创建连接并实例化连接对象和得到连接对象,我用构造函数对conn进行初始化,并写了GetConn()函数,把重复的内容提取出来是重构的重要工作。
Imports System.Data.SqlClient Imports System.Configuration Public Class SQLHelper Private conn As SqlConnection Private cmd As SqlCommand Private sdr As SqlDataReader '构造函数 Sub New() 'Dim connStr As String = "Data Source=localhost;Initial Catalog=NewCharge;Persist Security Info=True;User ID=sa;Password=123456" Dim connstr As String = System.Configuration.ConfigurationManager.AppSettings("connStr") conn = New SqlClient.SqlConnection(connstr) End Sub Private Function GetConn() As SqlConnection If conn.State = ConnectionState.Closed Then conn.Open() Return conn Else Return conn End If End Function
在SQLHelper中主要有四类,分别是
不带参数的sql增删改语句或存储过程(无返回行或值)
带参数的sql增删改语句或存储过程(无返回行或值)
不带参数的sql查询语句或存储过程,返回DataTable结果集(有返回行或值)
带参数的sql查询语句或存储过程,返回DataTable结果集(有返回行或值)
下面是我写的第一个不带参数的sql增删改语句
''' <summary> ''' 执行不带参数的sql增删改语句 ''' </summary> ''' <param name="sql">sql语句</param> ''' <returns></returns> ''' <remarks></remarks> Public Function ExecuteNonQuery(ByVal sql As String) As Boolean Dim conn = GetConn() Dim cmd As SqlCommand = New SqlCommand(sql, conn) If cmd.ExecuteNonQuery() > 0 Then conn.Close() Return True Else Return False End If End Function
事实上我们常使用的不只有sql语句,还包括存储过程。所以,sql语句变成了cmdText,而究竟是sql语句还是存储过程则要看cmdType,需要给函数增加一个参数。因此对该函数做如下重构
''' <summary> ''' 执行不带参数的sql增删改语句或存储过程 ''' </summary> ''' <param name="cmdtxt">增删改语句或存储过程</param> ''' <param name="cmdtype">命令类型文本或存储过程</param> ''' <returns>受影响的行数</returns> ''' <remarks></remarks> Public Function ExecuteNonQuery(ByVal cmdtxt As String, ByVal cmdtype As CommandType) As Integer Dim conn = GetConn() '定义并得到一个数据库连接对象 Dim cmd As SqlCommand = New SqlCommand(cmdtxt, conn) '定义一个命令对象 cmd.CommandType = cmdtype Dim res As Integer Try res = cmd.ExecuteNonQuery() Catch ex As Exception MsgBox(ex.Message, , "数据库操作") Finally If conn.State = ConnectionState.Open Then '关闭数据库连接 conn.Close() End If End Try Return res End Function
在第二个方法中我用到了异常处理Try…Catch语句,其实抛异常主要是在BLL层,这里没多大必要。
其余三个方法如下:
''' <summary> ''' 执行带参数的sql增删改语句或存储过程 ''' </summary> ''' <param name="cmdtext">增删改语句或存储过程</param> ''' <param name="cmdtype">命令类型文本或存储过程</param> ''' <param name="paras">参数数组</param> ''' <returns>受影响的行数</returns> ''' <remarks></remarks> Public Function ExecuteNonQuery(ByVal cmdtext As String, ByVal cmdtype As CommandType, ByVal paras As SqlParameter()) As Integer Dim conn = GetConn() Dim cmd As SqlCommand = New SqlCommand(cmdtext, conn) Dim res As Integer cmd.CommandType = cmdtype cmd.Parameters.AddRange(paras) Try res = cmd.ExecuteNonQuery() Catch ex As Exception MsgBox(ex.Message, , "数据库操作") Finally If conn.State = ConnectionState.Open Then conn.Close() End If End Try Return res End Function ''' <summary> ''' 执行不带参数的sql查询语句或存储过程,返回DataTable结果集 ''' </summary> ''' <param name="cmdtext">sql查询语句或存储过程</param> ''' <param name="cmdtype">命令类型文本或存储过程</param> ''' <returns>返回DataTable结果集</returns> ''' <remarks></remarks> Public Function ExecuteQuery(ByVal cmdtext As String, ByVal cmdtype As CommandType) As DataTable Dim conn = GetConn() Dim cmd As SqlCommand = New SqlCommand(cmdtext, conn) Dim mydt As DataTable = New DataTable Dim myReader As SqlDataReader cmd.CommandType = cmdtype myReader = cmd.ExecuteReader() mydt.Load(myReader) Return mydt conn.Close() End Function ''' <summary> ''' 执行带参数的sql查询语句或存储过程,返回DataTable结果集 ''' </summary> ''' <param name="cmdtext">sql查询语句或存储过程</param> ''' <param name="cmdtype">命令类型文本或存储过程</param> ''' <param name="paras">参数集合</param> ''' <returns>返回DataTable结果集</returns> ''' <remarks></remarks> Public Function ExecuteQuery(ByVal cmdtext As String, ByVal cmdtype As CommandType, ByVal paras As SqlParameter()) As DataTable Dim conn = GetConn() Dim cmd As SqlCommand = New SqlCommand(cmdtext, conn) Dim mydt As DataTable = New DataTable Dim myReader As SqlDataReader cmd.CommandType = cmdtype cmd.Parameters.Add(paras) myReader = cmd.ExecuteReader() mydt.Load(myReader) Return mydt conn.Close() End Function
其实在三层架构的思想下开发系统,既然我们定义了实体类,严格的说就要全部返回实体类而不是DataTable、DataSet等,那我们都知道用DataTable非常简单只需要load(sqlDatareader)一下就可以了,而返回实体类则需要写N多行代码,但是正如三层的划分,UI层是不知道各个表的字段的,所以传DataTable违背了三层的原则。那怎么办呢?办法就是在DAL层将结果赋值给实体类,然后再传回UI层。当然很费事了,如果要学习就老老实实传实体吧,如果要效率,传DataTable也未可厚非。