MVC系列之二 Model層細解


一、簡介

  在上一篇將MVC的時候,有很有朋友對簡單三層的概念不是很熟悉,因此,今天進行簡單三層的一個簡單介紹,同時為理解MVC中的Model做知識累計。

  傳統的三層主要指的是UI層,BLL層,DAL層:

  1. UI層:與用戶進行交互的前台層,主要負責展示數據給前台,以及接受數據到后台。
  2. BLL層:可以叫它業務層,主要負責處理業務邏輯,比如說數據的校驗等等操作。
  3. DAL層:很重要的數據訪問層,主要負責和數據庫進行交互,完成數據的讀取以及寫入等操作。

  這里沒有提到Models,可能會有人感到驚奇,Models是三層的概念,但不是三層的層概念,Models是一個存放實體類型的層。

  上面是理論概念,下面再講下他們之間的調用關系,然后我們就上一些例子來促進理解。。。。。。

 對上圖進行簡單的介紹:這樣的分層,主要目的是將業務邏輯和數據訪問進行一個分離。如果不進行這樣的分層,混合在一起,當你的數據庫進行一下調整,你就需要將所有進行數據訪問的地方都修改,那就太痛苦了,你會有瘋了的沖動,嘿嘿。但是,如果這樣分層后,你只需要修改DAL層里面的方法,BLL不需要修改,是不是感覺到一點分層的意義了。

 

二、代碼層面理解

  我們先理解下Model實體,這個可是貫穿三層的東東,下面來看下一張數據表:

  可以對應的實體類,來看看,我們在構造實體類的時候,要注意類型對應:

//============================================================
//author:zhujinghui
//============================================================

using System;
using System.Collections.Generic;
using System.Text;

namespace ZJH.ThreeLayer.Models
{    
    [Serializable()]
    public class UserInfo
    {//UserInfo對應表名,這個不硬性規定,但是約定俗成    
            public int ID
            {
                get;
                set;
            }
            public string UName
            {
                get;
                set;
            }
            public string UPwd
            {
                get;
                set;
            }
            //這里值得注意,在數據庫中是可以為null,在類型中對應int?可空類型
            public int? UAge
            {
                get;
                set;
            }
            public DateTime SubTime
            {
                get;
                set;
            }
            public bool DelFalg
            {
                get;
                set;
            }
            public string Remark
            {
                get;
                set;
            }
    }
}
Model實體類

  有沒有沒看出什么,我們這里的思想很重要:我們將一張表  和  一個類  進行了對應:

  1. 類名我們對應表名
  2. 類屬性對應表字段,字段相應的類型對應
  3. 可空值類型的問題

  每一張表可以對應出一個類,而表里面的數據就是實例出的一個個實體,表里面的數據集就相當於實體集合。

 

 三、DAL層的理解

  是主要的數據訪問層,在這一層中我們主要和數據進行交互,看下面的DAL代碼,我們這里主要放了一個方法,就是GetById,通過ID來獲得相應的實體數據。

  ToModel這個方法比較靈活,在使用的時候。

//============================================================
//author:zhujinghui
//============================================================

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using ZJH.ThreeLayer.Models;

namespace ZJH.ThreeLayer.DAL
{
    public partial class UserInfoDAL
    {
        //這里我們設置一個方法,還有很多方法,比如增加刪除修改,通過ID得到相應的Model實體
        public UserInfo GetByID(int iD)
        {
            string sql = "SELECT * FROM UserInfo WHERE ID = @ID";
            using(SqlDataReader reader = SqlHelper.ExecuteDataReader(sql, new SqlParameter("@ID", iD)))
            {
                if (reader.Read())
                {
                    return ToModel(reader);
                }
                else
                {
                    return null;
                }
               }
        }
        
        //通過一個SqlDataReader得到UserInfo 的 Model
        public UserInfo ToModel(SqlDataReader reader)
        {
            UserInfo userInfo = new UserInfo();

            userInfo.ID = (int)ToModelValue(reader,"ID");
            userInfo.UName = (string)ToModelValue(reader,"UName");
            userInfo.UPwd = (string)ToModelValue(reader,"UPwd");
            userInfo.UAge = (int?)ToModelValue(reader,"UAge");
            userInfo.SubTime = (DateTime)ToModelValue(reader,"SubTime");
            userInfo.DelFalg = (bool)ToModelValue(reader,"DelFalg");
            userInfo.Remark = (string)ToModelValue(reader,"Remark");
            return userInfo;
        }
        
        //這里是處理null值對應數據中的DBNull值
        public object ToDBValue(object value)
        {
            if(value==null)
            {
                return DBNull.Value;
            }
            else
            {
                return value;
            }
        }
        
        //這里是處理數據中的DBNull值對應C#中德null值
        public object ToModelValue(SqlDataReader reader,string columnName)
        {
            if(reader.IsDBNull(reader.GetOrdinal(columnName)))
            {
                return null;
            }
            else
            {
                return reader[columnName];
            }
        }
    }
}
DAL層代碼

  相應的SqlHelper,SqlHelper在初學的時候是很重要的,需要仔細理解,這里是Dal層里面和底層數據庫交互最密切的類了,在里面主要是Ado.Net操作Sql數據庫的操作,這里面需要理解好后,封裝出dal層,dal層一般放增刪查改等方法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Configuration;
using System.Data.SqlClient;
using System.Data;
using System.Reflection;

namespace ZJH.ThreeLayer.DAL
{
    class SqlHelper
    {
       /// <summary>
        /// 准備連接字符串
        /// </summary>
        public static readonly string ConnStr = ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString;

        #region 1.0執行查詢多行語句 - 返回數據表 - public static DataTable ExecuteDataTable(string sqlSelectCmd, params SqlParameter[] parameters)
        /// <summary>
        /// 1.0執行查詢多行語句 - 返回數據表
        /// </summary>
        /// <param name="sqlSelectCmd">查詢sql命令</param>
        /// <param name="parameters">查詢參數</param>
        /// <returns>DataTable查詢數據表</returns>
        private static DataTable ExecuteDataTable(string sqlSelectCmd, CommandType cmdType, params SqlParameter[] parameters)
        {
            //1.創建連接通道
            using (SqlConnection conn = new SqlConnection(ConnStr))
            {
                //2.創建適配器
                SqlDataAdapter da = new SqlDataAdapter(sqlSelectCmd, conn);
                da.SelectCommand.CommandType = cmdType;
                //2.1設置查詢命令的參數
                if (parameters != null && parameters.Length > 0)
                    da.SelectCommand.Parameters.AddRange(parameters);
                //3.數據條
                DataTable table = new DataTable();
                //4.將查詢數據填充到數據表中
                da.Fill(table);
                return table;
            }
        }
        /// <summary>
        /// 執行查詢多行語句 - 返回數據表
        /// </summary>
        /// <param name="sqlSelectCmd">查詢sql命令</param>
        /// <param name="parameters">查詢參數</param>
        /// <returns>DataTable查詢數據表</returns>
        public static DataTable ExecuteDataTable(string sqlSelectCmd, params SqlParameter[] parameters)
        {
            return ExecuteDataTable(sqlSelectCmd, CommandType.Text, parameters);
        }
        /// <summary>
        /// 存儲過程執行查詢 - 返回單一數據表
        /// </summary>
        /// <param name="procedureName">存儲過程名</param>
        /// <param name="parameters">參數,注意傳出參數的方向</param>
        /// <returns>結果集</returns>
        public static DataTable ExecuteDataTableSP(string procedureName, params SqlParameter[] parameters)
        {
            return ExecuteDataTable(procedureName, CommandType.StoredProcedure, parameters);
        }
        #endregion

                /// <summary>
        /// 1.1升級版-泛型版 ---- 執行查詢多行語句 - 返回list集合
        /// </summary>
        /// <typeparam name="T2">泛型類型</typeparam>
        /// <param name="sqlSelectCmd">查詢sql命令</param>
        /// <param name="parameters">查詢參數</param>
        /// <returns>泛型集合</returns>
        private static List<T2> ExecuteList<T2>(string sqlSelectCmd, CommandType cmdType, params SqlParameter[] parameters)
        {
            //1.創建連接通道
            using (SqlConnection conn = new SqlConnection(ConnStr))
            {
                //2.創建適配器
                SqlDataAdapter da = new SqlDataAdapter(sqlSelectCmd, conn);
                da.SelectCommand.CommandType = cmdType;
                //2.1設置查詢命令的參數
                if (parameters != null && parameters.Length > 0)
                {
                    da.SelectCommand.Parameters.AddRange(parameters);
                }
                //3.數據表
                DataTable dt = new DataTable();
                //4.將查詢結果填充到數據表中
                if (conn.State == ConnectionState.Closed)
                {
                    conn.Open();
                }
                da.Fill(dt);
                //5.將DataTable轉成泛型集合List<T2>
                if (dt.Rows.Count > 0)
                {
                    //6.創建泛型集合對象
                    List<T2> list = new List<T2>();
                    //7.遍歷數據表的每一行,將行數據存放到 實體對象中,並且添加到 泛型集合中list
                    foreach (DataRow row in dt.Rows)
                    {
                        //7.1先獲得泛型的類型(里面包括類的所有信息----有什么屬性,有什么方法,有什么字段等等)
                        Type t = typeof(T2);
                        //7.2根據類型創建相應的該類型的對象
                        T2 model = (T2)Activator.CreateInstance(t);
                        //7.3根據類型獲得該類型的所有屬性
                        PropertyInfo[] properties = t.GetProperties();
                        //7.4遍歷所有的屬性數組
                        foreach (PropertyInfo p in properties)
                        {
                            //7.4.1獲得所有屬性的名字
                            string colName = p.Name;
                            //7.4.2根據列名,獲得當前循環行對應的值
                            object colValue = row[colName];
                            //7.4.3將 列值 賦給 model對象的p屬性
                            //考慮一下DBNULL的問題
                            p.SetValue(model, FromDbValue(colValue), null);
                        }
                        //7.5 將裝好 了行數據的 實體對象添加到 泛型集合中取
                        list.Add(model);
                    }

                    return list;
                }
            }
            return null;
        }
        /// <summary>
        /// 1.1升級版-泛型版 ---- 執行查詢多行語句 - 返回list集合
        /// </summary>
        /// <typeparam name="T2">泛型類型</typeparam>
        /// <param name="sqlSelectCmd">查詢sql命令</param>
        /// <param name="parameters">查詢參數</param>
        /// <returns>泛型集合</returns>
        public static List<T2> ExecuteList<T2>(string sqlSelectCmd, params SqlParameter[] parameters)
        {
            return ExecuteList<T2>(sqlSelectCmd, CommandType.Text, parameters);
        }
        /// <summary>
        /// 存儲過程執行ExecuteList,獲得list,通過反射
        /// </summary>
        public static List<T2> ExecuteListSP<T2>(string procedureName, params SqlParameter[] parameters)
        {
            return ExecuteList<T2>(procedureName, CommandType.StoredProcedure, parameters);
        }
        #endregion

        #region 2.執行查詢多行語句 -- 返回數據讀取器(輕量級)  - public static SqlDataReader ExecuteDataReader(string sqlSelectCmd, params SqlParameter[] parameters)
        /// <summary>
        /// 2.執行查詢多行語句 -- 返回數據讀取器(輕量級) 
        /// </summary>
        /// <param name="sqlSelectCmd">sql命令</param>
        /// <param name="parameters">命令參數</param>
        /// <returns>數據讀取器</returns>
        public static SqlDataReader ExecuteDataReader(string sqlSelectCmd, params SqlParameter[] parameters)
        {
            SqlConnection conn = null;
            SqlCommand cmd = null;
            try
            {
                //1.建立連接通道
                conn = new SqlConnection(ConnStr);
                //1.1打開連接
                conn.Open();
                //2.創建命令對象
                cmd = conn.CreateCommand();
                //3.添加命令語句
                cmd.CommandText = sqlSelectCmd;
                //4.添加命令參數
                if (parameters != null && parameters.Length > 0)
                {
                    cmd.Parameters.AddRange(parameters);
                }
                //5.創建讀取器(當關閉讀取器時候,會自動關閉連接通道)
                SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);

                //7.返回讀取器
                return dr;
            }
            catch (Exception ex)
            {
                conn.Dispose();
                throw ex;
            }
        }
        #endregion

        #region 3.執行非查詢語句(增刪改) -- public static int ExecuteNonQuery(string sqlSelectCmd, params SqlParameter[] parameters)
        private static int ExecuteNonQuery(string sqlSelectCmd, CommandType cmdType, params SqlParameter[] parameters)
        {
            //1.打開連接通道
            using (SqlConnection conn = new SqlConnection(ConnStr))
            {
                conn.Open();
                //2.建立SqlCommand連接
                using (SqlCommand cmd = conn.CreateCommand())
                {
                    //3.添加命令語句
                    cmd.CommandText = sqlSelectCmd;
                    cmd.CommandType = cmdType;
                    //4.添加命令參數
                    if (parameters != null && parameters.Length > 0)
                        cmd.Parameters.AddRange(parameters);
                    //5.執行sql命令
                    int count = cmd.ExecuteNonQuery();
                    return count;
                }
            }
        }
        /// <summary>
        /// 執行非查詢語句(增刪改)
        /// </summary>
        /// <param name="sqlSelectCmd">sql命令</param>
        /// <param name="parameters">命令參數</param>
        /// <returns></returns>
        public static int ExecuteNonQuery(string sqlSelectCmd, params SqlParameter[] parameters)
        {
            return ExecuteNonQuery(sqlSelectCmd, CommandType.Text, parameters);
        }
        /// <summary>
        /// 存儲過程執行exetcuteNonQuery
        /// </summary>
        public static int ExecuteNonQuerySP(string procedureName, params SqlParameter[] parameters)
        {
            return ExecuteNonQuery(procedureName, CommandType.StoredProcedure, parameters);
        }
        #endregion

        #region 4.查詢sql命令,返回數據結果集的第一行第一列的單值  public static object ExecuteScalar(string sqlSelectCmd, params SqlParameter[] parameters)
        /// <summary>
        /// 4.查詢sql命令,返回數據結果集的第一行第一列的單值
        /// </summary>
        /// <param name="sqlSelectCmd">sql命令</param>
        /// <param name="parameters">命令參數</param>
        /// <returns>單個值</returns>
        private static object ExecuteScalar(string sqlSelectCmd, CommandType cmdType, params SqlParameter[] parameters)
        {
            //1.建立連接通道
            using (SqlConnection conn = new SqlConnection(ConnStr))
            {
                //2.打開連接
                conn.Open();
                //3.建立Command
                using (SqlCommand cmd = conn.CreateCommand())
                {
                    //4.添加命令參數
                    if (parameters != null && parameters.Length > 0)
                        cmd.Parameters.AddRange(parameters);
                    //5.添加命令語句
                    cmd.CommandText = sqlSelectCmd;
                    cmd.CommandType = cmdType;
                    //6.執行查詢
                    object obj = cmd.ExecuteScalar();
                    return obj;
                }
            }
        }
        /// <summary>
        /// 查詢sql命令,返回數據結果集的第一行第一列的單值
        /// </summary>
        /// <param name="sqlSelectCmd">sql命令</param>
        /// <param name="parameters">命令參數</param>
        /// <returns>單個值</returns>
        public static object ExecuteScalar(string sqlSelectCmd, params SqlParameter[] parameters)
        {
            return ExecuteScalar(sqlSelectCmd, CommandType.Text, parameters);
        }
        /// <summary>
        /// 存儲過程查詢sql命令,返回數據結果集的第一行第一列的單值
        /// </summary>
        /// <param name="procedureName">存儲過程的名字</param>
        /// <param name="parameters">參數</param>
        /// <returns>單值</returns>
        public static object ExecuteScalarSP(string procedureName, params SqlParameter[] parameters)
        {
            return ExecuteScalar(procedureName, CommandType.StoredProcedure, parameters);
        }
        #endregion

  
        #region 5.0 從數據庫中讀取值,進行dbnull轉換成null public object FromDbValue(object obj)
        /// <summary>
        /// 從數據庫中讀取值,進行dbnull轉換成null
        /// </summary>
        /// <param name="obj">從數據庫讀取的值</param>
        /// <returns>返回值</returns>
        public static object FromDbValue(object obj)
        {
            if (obj == DBNull.Value)
            {
                return null;
            }
            else
            {
                return obj;
            }
        }
        #endregion

        #region 5.1 賦值寫入數據庫,進行null轉換成dbnull public object ToDbValue(object obj)
        /// <summary>
        /// 賦值寫入數據庫,進行null轉換成dbnull
        /// </summary>
        /// <param name="obj">要寫入數據庫中的對象</param>
        /// <returns>返回值</returns>
        public static object ToDbValue(object obj)
        {
            if (obj == null)
            {
                return DBNull.Value;
            }
            else
            {
                return obj;
            }
        }
        #endregion
    }
}
SqlHelper代碼

 

四、BLL層代碼

  這是邏輯層,負責將dal層傳過來的數據進行簡單的邏輯處理,可以參考代碼,主要是根據UI層需要進行什么邏輯處理,就在業務層進行處理,處理后根據結果進行邏輯判斷,返回UI層可以識別的返回值。

  

using System;
using System.Collections.Generic;
using System.Text;
using ZJH.ThreeLayer.DAL;
using ZJH.ThreeLayer.Models;

namespace ZJH.ThreeLayer.BLL
{

    public partial class UserInfoBLL
    {
       //這里是服務層,主要負責邏輯處理
        public UserInfo GetByID(int iD)
        {
            //這里還沒有詳細的邏輯處理,后面別的還有詳細的處理
            return new UserInfoDAL().GetByID(iD);
        }
        
        public bool DeleteByID(int id)
        {
        //關注這里,DeleteByID返回的數據是int,但是經過邏輯判斷的BLL層,返回的就是bool值,這只是簡單的邏輯判斷,需要根據你的業務返回對應的值
            if(new UserInfoDAL().DeleteByID(id)>0)
            {
                return true;
            }
            else
            {
                return false;
            }
        }
    }
}
BLL層代碼

 

五、MVC中對應的Model又指的是什么呢?

  我們在MVC里面指的Model是涵蓋了BLL, DAL和Models,負責數據處理的多層結構,一般情況我們都會將MVC中Model抽出不同的幾個類庫,而不是單純地在一個文件夾中。

 

 

 


免責聲明!

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



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