MVC系列之二 Model层细解
一、简介
在上一篇将MVC的时候,有很有朋友对简单三层的概念不是很熟悉,因此,今天进行简单三层的一个简单介绍,同时为理解MVC中的Model做知识累计。
传统的三层主要指的是UI层,BLL层,DAL层:
- UI层:与用户进行交互的前台层,主要负责展示数据给前台,以及接受数据到后台。
- BLL层:可以叫它业务层,主要负责处理业务逻辑,比如说数据的校验等等操作。
- 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实体类
有没有没看出什么,我们这里的思想很重要:我们将一张表 和 一个类 进行了对应:
- 类名我们对应表名
- 类属性对应表字段,字段相应的类型对应
- 可空值类型的问题
每一张表可以对应出一个类,而表里面的数据就是实例出的一个个实体,表里面的数据集就相当于实体集合。
三、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 > )
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 > )
{
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 > )
{
//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 > )
{
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 > )
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 > )
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)>)
{
return true;
}
else
{
return false;
}
}
}
}
BLL层代码
五、MVC中对应的Model又指的是什么呢?
我们在MVC里面指的Model是涵盖了BLL, DAL和Models,负责数据处理的多层结构,一般情况我们都会将MVC中Model抽出不同的几个类库,而不是单纯地在一个文件夹中。
MVC系列之二 Model层细解的更多相关文章
- <转>ASP.NET学习笔记之MVC 3 数据验证 Model Validation 详解
MVC 3 数据验证 Model Validation 详解 再附加一些比较好的验证详解:(以下均为引用) 1.asp.net mvc3 的数据验证(一) - zhangkai2237 - 博客园 ...
- MVC 3 数据验证 Model Validation 详解
在MVC 3中 数据验证,已经应用的非常普遍,我们在web form时代需要在View端通过js来验证每个需要验证的控件值,并且这种验证的可用性很低.但是来到了MVC 新时代,我们可以通过MVC提供的 ...
- (转)MVC 3 数据验证 Model Validation 详解
继续我们前面所说的知识点进行下一个知识点的分析,这一次我们来说明一下数据验证.其实这是个很容易理解并掌握的地方,但是这会浪费大家狠多的时间,所以我来总结整理一下,节约一下大家宝贵的时间. 在MVC 3 ...
- SpringBoot系列(十二)过滤器配置详解
SpringBoot(十二)过滤器详解 往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件 ...
- pureMVC简单示例及其原理讲解二(Model层)
本节将讲述Model层. Model层有VO和Mediator组成,非常简单,仅仅包含两个类:UserVO和UserProxy. UserVO中的构造器用于初始化用户的添加(通过email和密码),另 ...
- Carbondata源码系列(二)文件格式详解
在上一章当中,写了文件的生成过程.这一章主要讲解文件格式(V3版本)的具体细节. 1.字典文件格式详解 字典文件的作用是在存储的时候将字符串等类型转换为int类型,好处主要有两点: 1.减少存储占用空 ...
- Django中model层详解
#!/usr/bin/env python# _*_ coding:utf-8 _*_ from django.db import models class UserType(models.Model ...
- Spark源码系列(二)RDD详解
1.什么是RDD? 上一章讲了Spark提交作业的过程,这一章我们要讲RDD.简单的讲,RDD就是Spark的input,知道input是啥吧,就是输入的数据. RDD的全名是Resilient Di ...
- MyBatis系列:二、配置文件详解
本文会详细介绍MyBatis的常用配置 1.properties节点 <properties resource="mybatis-config.properties"> ...
随机推荐
- CSS_03_03_ul图片替换
ul图片替换 第01步:编写css样式:url.css @charset "utf-8"; /*ul用图片替换*/ ul.u_01{/*图片*/ list-style:circle ...
- SparkSQL JSON数据操作(1.3->1.4)
1.用户自定义schema data json串格式如下: { "partner_code": "demo", "app_name": &q ...
- 在GitHub上建立个人主页的方法(转载)
GitHub就不需要介绍了,不清楚可以百度一下.只说目前GitHub是最火的开源程序托管集中地了,连PHP的源码都在GitHub上面托管了(https://github.com/php ). GitH ...
- MVC4中给TextBoxFor设置默认值和属性
例如:(特别注意在设置初始值的时候 Value 中的V要大写) @Html.TextBoxFor(model => model.CustomerCode, new { Value=" ...
- angular 自定义指令 link
function link(scope, element, attrs) { ... } where: scope is an Angular scope object. element is the ...
- ThinkPHP讲解(一)框架基础
ThinkPHP框架知识点过于杂乱,接下来将以问题的形势讲解tp(ThinkPHP的简写) 1.tp框架是什么,为什么使用是它? 一堆代码的集合,里边有变量.函数.类.常量,里边也有许多设计模式MVC ...
- MySQL增删改查
C/S:Client ServerB/S:Brower Server php主要实现B/S .net IIS java TomCat LAMP: Linux系统 A阿帕奇服务器 Mysql数据库 Ph ...
- python生成数据库中所有表的DESC描述
在数据库设计完成之后, 常常需要在 wiki 或其他文档中保存一份数据库中所有表的 desc 描述, 尤其是每个字段的含义和用途. 手动去生成自然是不可取的. 因此, 我编写了一个简单的 python ...
- linux驱动的入口函数module_init的加载和释放【转】
本文转载自:http://blog.csdn.net/zhandoushi1982/article/details/4927579 就像你写C程序需要包含C库的头文件那样,Linux内核编程也需要包含 ...
- 【python cookbook】【字符串与文本】7.定义实现最短匹配的正则表达式
问题:使用正则表达式对文本模式匹配,将识别出来的最长的可能匹配修改为找出最短的可能匹配 解决方法:在匹配模式中的*操作符后加上?修饰符 import re # Sample text text = ' ...