ASP.NET三層結構演化構建之三——用了又用

當你看到那一堆煩人的數據庫操作的時候,是不是有一種想殺人的感覺呢。一定要淡定呀。

要對這個世界充滿信心的。生活這麼美好,畢竟還是有很多美女的。

封裝是面向對象的一個重要思想。微軟大爺提供了數據庫通用操作類。就是來解決這個問題的。就是將一些通用的數據庫操作封裝到一個類中。實現代碼的複用。這樣,在DAL的類中就再也看不到討厭的數據庫連接啦。哈哈。

新建一個項目,命名爲DBUtility,意思是數據庫通用模塊。

刪除自動生成的class1.cs,在裏面添加一個SQLHelper類。

 

微軟有提供這樣的類。源自微軟的示例項目PetShop。我現在就是使用PetShop裏的這個類。爲了簡明易懂,我將原版中的數據庫命令參數緩存功能和關於事物的那個部分去掉了。並且發揮了我超人的英語屎力,翻譯了一下原有的代碼備註。(翻譯的很爛,英語大牛莫拿板磚砸我)

 

SQLHelper內容如下:

 

using System;

using System.Configuration;

using System.Data;

using System.Data.SqlClient;

using System.Collections;

 

namespace DBUtility

{

 

    /// <summary>

    /// SqlHelper類的封裝是爲了取得高性能,包含可擴展的最常用的一些功能

    /// </summary>

    public abstract class SqlHelper

    {

        //數據庫連接字符串

        public static readonly string ConnectionStringLocalTransaction = ConfigurationManager.ConnectionStrings["SQLConnString"].ConnectionString;

 

        /// <summary>

        /// 根據指定的數據庫連接字符串以及提供的參數,執行一個SqlCommand(沒有返回結果集)

        /// </summary>

        /// <remarks>

        /// 例如:

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

        /// </remarks>

        /// <param name="connectionString">一個有效的數據庫連接字符串</param>

        /// <param name="commandType">命令類型(存儲過程,文本等)</param>

        /// <param name="commandText">存儲過程名或T-SQL命令</param>

        /// <param name="commandParameters">一個存放執行Sql命令的參數的數組</param>

        /// <returns>一個整數,表示受影響的行數</returns>

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

        {

 

            SqlCommand cmd = new SqlCommand();

 

            using (SqlConnection conn = new SqlConnection(connectionString))

            {

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

                int val = cmd.ExecuteNonQuery();

                cmd.Parameters.Clear();

                return val;

            }

        }

 

        /// <summary>

        /// 根據提供的參數,執行一個SqlCommand(沒有返回結果集)

        /// </summary>

        /// <remarks>

        /// 例如: 

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

        /// </remarks>

        /// <param name="conn">一個已經存在的數據庫連接</param>

        /// <param name="commandType">命令類型(存儲過程,文本等)</param>

        /// <param name="commandText">存儲過程名或T-SQL命令</param>

        /// <param name="commandParameters">一個存放執行Sql命令的參數的數組</param>

        /// <returns>一個整數,表示受影響的行數</returns>

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

        {

 

            SqlCommand cmd = new SqlCommand();

 

            PrepareCommand(cmd, connection, 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">命令類型(存儲過程,文本等)</param>

        /// <param name="commandText">存儲過程名或T-SQL命令</param>

        /// <param name="commandParameters">一個存放執行Sql命令的參數的數組</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

            {

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

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

                cmd.Parameters.Clear();

                return rdr;

            }

            catch

            {

                conn.Close();

                throw;

            }

        }

 

        /// <summary>

        /// 根據指定的數據庫連接字符串以及提供的參數,執行一個SqlCommand,返回記錄的第一行第一列數據

        /// </summary>

        /// <remarks>

        /// 例如:

        ///  Object obj = ExecuteScalar(connString, CommandType.StoredProcedure, "PublishOrders", new SqlParameter("@prodid", 24));

        /// </remarks>

        /// <param name="connectionString">一個有效的數據庫連接字符串</param>

        /// <param name="commandType">命令類型(存儲過程,文本等)</param>

        /// <param name="commandText">存儲過程名或T-SQL命令</param>

        /// <param name="commandParameters">一個存放執行Sql命令的參數的數組</param>

        /// <returns>一個需要被轉換爲所需類型的對象</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, 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">命令類型(存儲過程,文本等)</param>

        /// <param name="commandText">存儲過程名或T-SQL命令</param>

        /// <param name="commandParameters">一個存放執行Sql命令的參數的數組</param>

        /// <returns>一個需要被轉換爲所需類型的對象</returns>

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

        {

 

            SqlCommand cmd = new SqlCommand();

 

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

            object val = cmd.ExecuteScalar();

            cmd.Parameters.Clear();

            return val;

        }

 

        /// <summary>

        /// 準備一個要執行的命令

        /// </summary>

        /// <param name="cmd">命令對象</param>

        /// <param name="conn">連接對象</param>

        /// <param name="cmdType">命令類型, 例如:存儲過程,文本等</param>

        /// <param name="cmdText">命令內容, 例如:Select * from Products</param>

        /// <param name="cmdParms">命令參數</param>

        private static void PrepareCommand(SqlCommand cmd, SqlConnection conn, CommandType cmdType, string cmdText, SqlParameter[] cmdParms)

        {

 

            if (conn.State != ConnectionState.Open)

                conn.Open();

 

            cmd.Connection = conn;

            cmd.CommandText = cmdText;

 

            cmd.CommandType = cmdType;

 

            if (cmdParms != null)

            {

                foreach (SqlParameter parm in cmdParms)

                    cmd.Parameters.Add(parm);

            }

        }

    }

}

 

在這個數據庫輔助類中,使用了ConfigurationManager對網站配置文件web.config中的數據庫連接字符串進行讀取。就是這一句:

 

public static readonly string ConnectionStringLocalTransaction = ConfigurationManager.ConnectionStrings["SQLConnString"].ConnectionString;

 

所以我們的web.config中應該具有name屬性爲SQLConnString的數據庫連接字符串的XML結點。

 

打開web.config,找到<connectionStrings/>,並將其修改爲:

 

<connectionStrings>

    <add name="SQLConnString" connectionString="Data Source=.;Initial Catalog=StudentMIS;Integrated Security=True"/>

  </connectionStrings>

 

意思就是添加一個名爲SQLConnString的數據庫連接字符串。

這樣,我們就可以通過對web.config的訪問來獲取需要的數據庫連接字符串啦。

 

需要在DBUtility中添加對Configuration的引用,右擊DBUtility下的引用->添加引用,選擇.NET中的System.Configuation如圖:

 

然後點擊確定按鈕。這樣就可以在SQLHelper中對Configuration進行調用啦。

 

接下來我們對DAL中的User.cs進行修改。原先的複雜的數據庫操作全部通過調用DBUtility中的方法來實現。

 

首先當然是對DAL添加DBUtility的引用。這個同志們都很熟了吧。

 

修改後的User.cs如下:

 

using System;

using System.Data;

using System.Data.SqlClient;

using DBUtility;

 

namespace DAL

{

    public class User

    {

        private const string SQL_SELECT_PASSWORD_BY_USERID = "SELECT password FROM [User] WHERE UserId = @UserId";

        private const string SQL_SELECT_USERNAME_BY_USERID = "SELECT UserName FROM [User] WHERE UserId = @UserId";

        private const string PARM_USERID = "@UserId";

 

        /// <summary>

        /// 根據用戶Id獲取用戶密碼

        /// </summary>

        /// <param name="userId">用戶Id</param>

        /// <returns>用戶密碼</returns>

        public string GetUserPassword(string userId)

        {

            SqlParameter parm = new SqlParameter(PARM_USERID, SqlDbType.VarChar, 10);//參數UserId

            parm.Value = userId;//給參數賦值

            Object obj = SqlHelper.ExecuteScalar(SqlHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_SELECT_PASSWORD_BY_USERID, parm);

            if (obj != nullreturn obj.ToString();//若查詢結果不爲空,則將其轉換爲字符串

            else return null;//否則返回null

        }

 

        /// <summary>

        /// 根據用戶Id獲取用戶姓名

        /// </summary>

        /// <param name="userId">用戶Id</param>

        /// <returns>用戶姓名</returns>

        public string GetUserName(string userId)

        {

            SqlParameter parm = new SqlParameter(PARM_USERID, SqlDbType.VarChar, 10);//參數UserId

            parm.Value = userId;//給參數賦值

            Object obj = SqlHelper.ExecuteScalar(SqlHelper.ConnectionStringLocalTransaction, CommandType.Text, SQL_SELECT_USERNAME_BY_USERID, parm);

            if (obj != nullreturn obj.ToString();//若查詢結果不爲空,則將其轉換爲字符串

            else return null;//否則返回null

        }

    }

}

 

 

是不是感覺清爽了很多呢。修改起來也方便。

 

但是有個弊端。GetUserPassword方法返回的是一個string。如果寫數據庫處理的哥哥一個不小心,把對數據庫的操作的T-SQL寫錯了,這個錯誤仍然能返回一個string。這樣,那個哥哥找錯誤就比較痛苦了。因爲代碼沒有語法錯誤。編譯執行都能通過,就是效果出了問題。

爲此,得對DAL中函數的返回值進行規範。若出現了錯誤,編譯就無法通過。這樣那個哥哥就爽多了。

具體怎麼做請看下一篇博文:ASP.NET三層結構演化構建之四——你不是我,我不是他

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章