三層架構的搭建


                今天又是我們上課需要停留片刻的尾聲啦,頓時不知道該講些什么啦,總起來講,我們這周學習啦SQL Server語言以及ADO.net,學習啦這個也就意味着我們可以做些小程序啦,嘿嘿,我知道我現在做出來的程序還是錯誤居多,而且最重要的是一點都不嚴謹,我也不給自己找理由啦,還是自己練習的項目太少啦,接下來我們就會要項目啦,我想我會認真去做練習的,經過最近的程序發現我是很粗心啊,每次只要發生錯誤,都是沒有自己解決啊,我感覺我能夠幫其他的人找錯,可是自己的錯誤卻是難以發現啊,這是我現在最需要解決的問題啦,嘿嘿,說下今天吧,今天我們學習啦怎么創建三層架構以及三層架構的好處,另外,也做啦一下小例題啦,下面簡單總結下我前天發的那個小程序,我今天把它用三成架構方法做的。

          一.三層架構的了解    

—                 三層:UI(界面,User Interface)、BLL、DAL。Model是在三層之間進行數據傳遞的。在創建時間都是添加的類庫,和數據庫中的表一一對應的啦。UI層調用BLL、BLL調用DAL,數據用Model傳遞,UI不能直接調用DAL。Model不是一個層。在這里需要注意添加啦三層,就需要添加引用,UI層需要引用BLL層,BLL層需要引用DAL層,而不論是UI層,BLL層還是DAL層都要記得添加Model的引用啦。
          —DAL層只有SQL語句和數據處理,其他層一般不應該出現SQL語句以及和ADO.net相關的類。簡單的BLL只是調用DAL,但是BLL不是打醬油的:數據校驗應該放到BLL;BLL也會組合DAL成新的操作,比如ChangePassword。
—          DAL層中只有和數據庫操作的代碼。BLL中才有具體的邏輯
—          三層和所有代碼寫在一起的區別就像分工明確的麥當勞和收錢、做飯一起的賣煎餅的區別。
—          三層一般會比不分層慢,但是為了分工明確,這樣的少量的性能下降是可以的,很多時候效率不是唯一追求的因素。
          下面就簡單的寫下我把前面寫的登陸注冊以及顯示注冊用戶信息的那個小程序改寫的三層架構啦。
          二.具體的實例以及遇到的問題
          先寫一下搭建的三層的模式,UI層其實就是我們啟動程序時間看到的界面所以先寫一下BLL,DAL以及Model層啦。
public class Registerbll
    {
        Registerdal dal = new Registerdal();
        /// <summary>
        /// 登錄
        /// </summary>
        /// <param name="name">用戶名參數</param>
        /// <param name="pwd">密碼參數</param>
        /// <returns></returns>
        public bool GetLogin(string name, string pwd)
        {
            return dal.GetLogin(name, pwd);
        }
        /// <summary>
        /// 獲取用戶的注冊信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public bool GetReg( Registermodel model )
        {
            return dal.GetReg(model);
        }
        /// <summary>
        /// 獲取所有注冊用戶的信息
        /// </summary>
        /// <returns></returns>
        public DataTable GetAllInfo()
        {
            return dal.GetAllInfo();
        }
        /// <summary>
        /// 刪除選中用戶的注冊信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool GetUserInfo(int id)
        {
            return dal.GetUserInfo(id);
        }

        /// <summary>
        /// 修改注冊用戶的注冊信息
        /// </summary>
        /// <param name="model">調用的model類</param>
        /// <returns></returns>
        public bool GetUpdateInfo( Registermodel model)
        {
            return dal.GetUpdateInfo(model);
        }
        /// <summary>
        /// 獲取選中的用戶的信息顯示在更新頁面上
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public SqlDataReader Get(int id)
        {
            return dal.Get(id);
        }
    }

                 

             這里就是創建的Bll層,其實我個人認為他就是一個過渡啦,只用來調用DAL層的方法啦,不過嘛橋梁的作用啦也是至關重要的啦,所以在這里我們注意啦。下面看下DAL層的代碼:

public class Registerdal
    {
        /// <summary>
        /// 用聚合函數形式查詢用戶名和密碼是否存在的方法(登錄)
        /// </summary>
        /// <param name="name">用戶名</param>
        /// <param name="pwd">密碼</param>
        /// <returns></returns>
        public  bool GetLogin(string name,string pwd)
        {
            string  sql= "select count(*) from Register where username=@name and pwd=@pwd";
            SqlParameter[] sp ={
                                    new SqlParameter("@name",name),
                                    new SqlParameter("@pwd",pwd)
                                };
            int i = SqlHelper.ExcuteScalar(sql,sp);
            if (i > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 獲取用戶的注冊信息
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        public bool GetReg(Registermodel model)
        {
            //Id, UserName, Pwd, Age, Address, Phone, Sex
            string sql = "insert into Register(UserName,Pwd,Age,Address,Phone,Sex)values(@name,@pwd,@age,@address,@phone,@sex)";
            SqlParameter[]  sp ={
                                    new SqlParameter("@name",model.UserName),
                                    new SqlParameter("@pwd",model.Pwd),
                                    new SqlParameter("@age",model.Age),
                                    new SqlParameter("@address",model.Address),
                                    new SqlParameter("@phone",model.Phone),
                                    new SqlParameter("@sex",model.Sex),
                               };
            int i = SqlHelper.ExcuteNonQuery(sql,sp);
            if (i > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 獲取所有用戶的信息
        /// </summary>
        /// <returns></returns>
        public DataTable GetAllInfo()
        {
            string sql = "select * from  Register";
            return SqlHelper.ExcuteDataTable(sql);
        }
        /// <summary>
        /// 刪除選中的用戶的信息
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public bool GetUserInfo(int id)
        {
            string sql = "delete from register where Id=@id";
            SqlParameter sp = new SqlParameter("@id",id);
            if (SqlHelper.ExcuteNonQuery(sql, sp) > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 更改用戶已注冊過的信息
        /// </summary>
        /// <param name="id">用戶注冊信息的Id</param>
        /// <returns></returns>
        public bool GetUpdateInfo(Registermodel model)
        {
            string sql = "update Register set UserName=@name,pwd=@pwd,age=@age,sex=@sex,address=@address,phone=@phone where id=@id";
            SqlParameter[] sp ={ 
                                   new SqlParameter("@name",model.UserName),
                                   new SqlParameter("@pwd",model.Pwd),
                                   new SqlParameter("@age",model.Age),
                                   new SqlParameter("@sex",model.Sex),
                                   new SqlParameter("@address",model.Address),
                                   new SqlParameter("@phone",model.Phone),
                                   new SqlParameter("id",model.Id)
                               };
            if (SqlHelper.ExcuteNonQuery(sql, sp) > 0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
        /// <summary>
        /// 獲取選中的用戶的信息顯示在更新頁面上
        /// </summary>
        /// <param name="id">用戶注冊信息的Id</param>
        /// <returns>返回SqlDataReader類型</returns>
        public SqlDataReader Get(int id)
        {
            string sql = "select * from register where id=@id";
            SqlParameter sp = new SqlParameter("id",id);
            return SqlHelper.ExcuteSqlDataReader(sql,sp);
        }
    }

               

                 在DAL層中主要就是顯示我們的方法的,例如,sql語句啦,以及傳參啦這些方法是存儲在我們的DAL層的,而在DAL層中我們的SqlHelper類也是存在這里的,這個我之前是不知道的,也甚是奇怪的,但是通過接下來的學習我知道啦,在DAL層是寫方法的,而方法中存在與服務器的鏈接的啦,而把sq語句一般在DAL層中,這樣調用起來SqlHelper也是很方便的啦,嘿嘿。下面就詳細的說看下我的SqlHelper的類啦。

public class SqlHelper
    {
        /// <summary>
        /// 在配置文件中獲取連接字符串
        /// </summary>
        static string connection = ConfigurationManager.ConnectionStrings["sql"].ToString();
        /// <summary>
        /// 連接數據庫
        /// </summary>
        /// <param name="sql">sql語句</param>
        /// <param name="sp">sql語句中的參數</param>
        /// <returns>單行單列的值</returns>
        public static int ExcuteScalar(string sql, params SqlParameter[] sp)
        {
            using (SqlConnection conn = new SqlConnection(connection))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand(sql, conn))
                {
                    cmd.Parameters.AddRange(sp);
                    return Convert.ToInt32(cmd.ExecuteScalar());
                }
            }
        }
        /// <summary>
        /// 返回一個非查詢的int類型
        /// </summary>
        /// <param name="sql">sql查詢語句參數</param>
        /// <param name="sp">參數</param>
        /// <returns>受影響的行數</returns>
        public static int ExcuteNonQuery(string sql, params SqlParameter[] sp)
        {
            using (SqlConnection conn = new SqlConnection(connection))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand(sql, conn))
                {
                    cmd.Parameters.AddRange(sp);
                    return cmd.ExecuteNonQuery();
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="sp"></param>
        /// <returns>DataTable類型的值</returns>
        public static DataTable ExcuteDataTable(string sql, params SqlParameter[] sp)
        {
            using (SqlConnection conn = new SqlConnection(connection))
            {
                conn.Open();
                using (SqlCommand cmd = new SqlCommand(sql, conn))
                {
                    cmd.Parameters.AddRange(sp);

                    DataTable dt = new DataTable();
                    using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
                    {
                        adapter.Fill(dt);
                    }
                    return dt;
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sql"></param>
        /// <param name="sp"></param>
        /// <returns>返回一個SqlDataReader類型的值</returns>
        public static SqlDataReader ExcuteSqlDataReader(string sql, params SqlParameter[] sp)
        {
            SqlConnection conn = new SqlConnection(connection);
            conn.Open();
            using (SqlCommand cmd = new SqlCommand(sql, conn))
            {
                cmd.Parameters.AddRange(sp);
                SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
                return reader;
            }
        }
    }

 

                  在SqlHelp這個類中我們需要注意的有三點啦,第一,就是using的使用,使用using其實就是釋放啦他的資源,感覺使用這個釋放資源很方便的啦,而不需要在使用Dispose啦在程序最后;第二,就是最后一個方法在SqlConnection處就不能釋放資源啦,SqlDataReader是每次僅僅讀取一條信息,而且獨占以資源,所以我們只需要在他完全讀取完信息釋放資源即可,所以就是使用的CommandBehavior.CloseConnection;第三,就是我自己的錯誤啦,之前記得很清楚params SqlParameter[] 是一個可以傳多參同類型的,但是卻忘記啦,也可以不傳參數的,結果就重載啦一個方法,這就是我下次再寫程序時間需要注意的地方啦。接下來說一下Model層的使用啦。

public class Registermodel
    {
        public int Id { set; get; }
        public string UserName { set; get; }
        public string Pwd { set; get; }
        public int  Age { set; get; }
        public string Address { set; get; }
        public string Phone { set; get; }
        public bool Sex { set; get; }
    }

                 

            我們只是剛接觸程序啦,據說在在做項目前是要先創建表的啦,然后接下啦程序員就要先創建Model啦,而Model層創建時間一般就是和表的列一一對應的啦,這樣我們在調用很多參數時間可以直接使用Model實例化對象啦,嘿嘿,這樣會更簡單啦。下面就說下我們的UI層啦,首先寫一下UI層的登錄頁面啦。

                       

    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        
        private void Form1_Load(object sender, EventArgs e)
        {

        }
        Registerbll bll = new Registerbll();
        /// <summary>
        /// 用戶登錄
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnlog_Click(object sender, EventArgs e)
        {
            string username = this.txtname.Text.Trim();
            string pwd = this.textBox1.Text.Trim();
            MD5 md5 = new MD5CryptoServiceProvider();   //創建MD5的加密對象
            byte[] bytes = Encoding.Default.GetBytes(pwd);//把要進行MD5加密的字符串轉換成字節數組
            byte[] bytess = md5.ComputeHash(bytes);
            pwd = BitConverter.ToString(bytess).Replace("-", "");

            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(pwd))
            {
                MessageBox.Show("用戶名或者密碼不能為空");
            }
            else
            {
                if (bll.GetLogin(username, pwd))
                {
                    MessageBox.Show("登錄成功");
                    UserInfo info = new UserInfo();
                    info.Show();
                    this.Hide();
                }
                else
                {
                    MessageBox.Show("登錄失敗");
                }
            }
        }
        /// <summary>
        /// 跳轉到注冊信息界面
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnreg_Click(object sender, EventArgs e)
        {
            Register r = new Register();
            r.Show();
            this.Hide();
        }

        /// <summary>
        /// 發生鼠標點擊事件則使文本框中的“用戶名”三個字去掉
        /// 字體顏色為黑色
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void txtname_MouseEnter(object sender, EventArgs e)
        {
            this.txtname.Text = string.Empty;
            this.txtname.ForeColor = Color.Black;
        }
        /// <summary>
        /// 發生鼠標點擊事件則使文本框中的“密碼”兩個字去掉
        /// 設置文本框密碼信息樣式為*顯示
        /// 字體顏色為黑色
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void textBox1_MouseEnter(object sender, EventArgs e)
        {
            this.textBox1.Text = string.Empty;
            this.textBox1.PasswordChar = '*';
            this.textBox1.ForeColor = Color.Black;
        }
    }

                   

            這就是我使用三層寫的登錄界面的方法啦,嘿嘿,在這離需要注意的是我的密碼通過一個方法加密成啦32位的密碼啦,所以我們在登錄時間也需要把密碼加密啦,這樣才能和注冊時間存儲在數據庫的密碼信息匹配,致使登陸成功啦。這個是一定要注意的啦。當然,如果還沒用注冊用戶,那么我們可以直接點擊注冊按鈕注冊信息啦。下面我們就來看下UI層的注冊頁面啦。          

public partial class Register : Form
    {
        public Register()
        {
            InitializeComponent();
        }
          Registerbll bll = new Registerbll();
          Registermodel model = new Registermodel();
        /// <summary>
        /// 用戶注冊
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
          bool b = false;
          int  id = 0;
          public Register(int id,string name,string pwd,int age,bool sex,string address,string phone)
          {
              InitializeComponent();
              b = true;

              this.txtUserName.Text = name;
              this.txtpwd.Text = pwd;
              this.txtphone.Text = phone;
              string birthday = this.dateTimePicker1.Text;
              this.txtaddress.Text = address;
              this.id = id;
              if (sex.Equals("false"))
              {
                  this.radioButton2.Checked = true;
              }
              else
              {
                  this.radioButton1.Checked = true;
              }
          }

        private void btnreg_Click(object sender, EventArgs e)
        {
            string name = this.txtUserName.Text.Trim();
            string pwd = this.txtpwd.Text.Trim();
            MD5 md5 = new MD5CryptoServiceProvider();   //創建MD5的加密對象
            byte[] bytes = Encoding.Default.GetBytes(pwd);//把要進行MD5加密的字符串轉換成字節數組
            byte[] bytess = md5.ComputeHash(bytes);
            pwd = BitConverter.ToString(bytess).Replace("-", "");

            string birthday=this.dateTimePicker1.Text;
            string address = this.txtaddress.Text;
            string phone = this.txtphone.Text;
            int age = DateTime.Now.Year - DateTime.Parse(birthday).Year;
            bool sex=this.radioButton1.Checked ? true : false;
            if (!b)
            {
                if (string.IsNullOrEmpty(name) && string.IsNullOrEmpty(pwd) && string.IsNullOrEmpty(birthday) && string.IsNullOrEmpty(address) && string.IsNullOrEmpty(phone))
                {
                    MessageBox.Show("注冊信息為空");
                }
                else
                {
                    model.UserName = name;
                    model.Pwd = pwd;
                    model.Age = age;
                    model.Address = address;
                    model.Phone = phone;
                    model.Sex = sex;
                    if (bll.GetReg(model))
                    {
                        MessageBox.Show("注冊成功");
                    }
                    else
                    {
                        MessageBox.Show("注冊失敗");
                    }
                }
            }
            else
            {
                model.UserName = name;
                model.Pwd = pwd;
                model.Age = age;
                model.Address = address;
                model.Phone = phone;
                model.Sex = sex;
                if (bll.GetUpdateInfo(model))
                {
                    MessageBox.Show("更新成功");
                }
                else
                {
                    MessageBox.Show("更新失敗");
                }
            }
        }
    }

 

                  在注冊頁面我們需要注意一個非常重要的問題就是注冊信息需要獲取很多參數,而每次我們要傳參需要寫很多參數也是很麻煩的啦,那么這時間我們搭建的三層呢過架構中的model層就可以只用啦,我們只需要在UI層實例化一個對象,然后再傳參時間使用對象model來傳參,這樣使用起來更加說明啦三層是很方便的啦,嘿嘿。下面還有一個UI層頁面就是我們的顯示注冊用戶信息的頁面啦,再來總結一下啦。

public partial class UserInfo : Form
    {
        public UserInfo()
        {
            InitializeComponent();
        }
        Registerbll bll = new Registerbll();
        /// <summary>
        /// 心事注冊過的用戶的所有信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void UserInfo_Load(object sender, EventArgs e)
        {
            DataTable dt = bll.GetAllInfo();
            //像get什么的一般返回的是集合或者是datatable 
            //增刪改一般返回bool類型的  
            foreach (DataRow item in dt.Rows)
            {
                string format = string.Format("{0},{1},{2},{3},{4},{5},{6}", item[0], item[1], item[2], item[3], item[4], item[5], item[6]);
                this.listBox1.Items.Add(format);
            }
        }
        /// <summary>
        /// 刪除用戶信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btndel_Click(object sender, EventArgs e)
        {
            string aa = this.listBox1.SelectedItem.ToString();
            string[] bb = aa.Split(',');
            int id = int.Parse(bb[0]);
            if (bll.GetUserInfo(id))
            {
                UserInfo form = new UserInfo();
                MessageBox.Show("刪除成功");
            }
            else
            {
                MessageBox.Show("刪除失敗");
            }
        }
        /// <summary>
        /// 添加用戶信息,在這里調用啦注冊頁面的方法
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void butadd_Click(object sender, EventArgs e)
        {
            Register r = new Register();
            r.Show();
            this.Hide();
        }
        /// <summary>
        /// 更改注冊過的用戶信息
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnupd_Click(object sender, EventArgs e)
        {
            string aa = this.listBox1.SelectedItem.ToString();
            string[] bb = aa.Split(',');
            int id = int.Parse(bb[0]);
            SqlDataReader reader = bll.Get(id);
            if (reader.HasRows)
            {
                if (reader.Read())                //在這里我需要判斷是否讀取啦
                {
                    string name = Convert.ToString(reader[0]);
                    string pwd = Convert.ToString(reader[1]);
                    int age = Convert.ToInt32(reader[2]);
                    bool sex = Convert.ToInt32(reader[3]) == 0 ? false : true;
                    string address = Convert.ToString(reader[4]);
                    string phone = Convert.ToString(reader[5]);
                    Register r = new Register(id,name, pwd, age, sex, address, phone);
                    r.Show();
                    r.Text = "修改";
                    r.Btnreg.Text = "更新";
                    this.Hide();
                }
            }
        }
    }

 

                     在這個頁面中也是遇到啦很多問題,不知道是不是應該心存僥幸現在遇到的問題越多越好啦,然后我就可以發現更多的問題那,嘿嘿。在這個頁面中首先是在做ListBox顯示注冊用戶信息時間寫的DAL和DLL層的返回值類型不對,導致在UI層使用DataTable類型的參數就不能便利出每一項啦,在這里我的返回值類型使用起來還是不熟悉啦,這個要多加練習的啦;然后就是在修改信息上面SqlDataReader reader = bll.Get(id);這個本來是先通過獲取選中的用戶的id來讀取要修改的用戶的注冊信息,然后顯示在頁面上,進而我們進行更改的,但是那時間可能着急啦就直接調用啦更改用戶信息的方法,結果數在Get方法中傳啦所有參數(id,name, pwd, age, sex, address, phone),后來通過調試才發現的,然后就再次添加啦一個查詢用戶信息的方法,就是這樣我們這個小程序才完成的。

                      這個就是winform的三層架構方法的創建啦,感覺還好啦,雖然在做這個時間遇到啦很多問題,我還是一個一個給它解決啦,感覺蠻高興的啦,嘿嘿,還是感覺無論過程怎么樣,最后完成啦,所有的一切都滿是歡樂啦,嘿嘿。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM