zoukankan      html  css  js  c++  java
  • 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抽出不同的几个类库,而不是单纯地在一个文件夹中。

  • 相关阅读:
    英文半字节压缩编码技术
    博弈翻硬币游戏
    POJ 2015 Permutation Code
    8051、ARM和DSP指令周期的测试与分析
    Huffman编码
    CentOS 命令提示符颜色及样式详解
    JAVA程序员面试32问
    面向抽象编程:接口和抽象类
    初学实用:实例讲解Java中的接口的作用
    C#和Java的区别
  • 原文地址:https://www.cnblogs.com/zhujinghui/p/3388717.html
Copyright © 2011-2022 走看看