数据库三层模型

1,什么是三层?

2,为什么使用三层?

3,三层与以往使用的两层相比有什么不同?它的优势在哪里?

4,如何学好三层?如何应用三层?

先了解:

1、什么是三层

UI(表现层):主要是指用户交互的界面。用于接收用户输入的数据和显示处理后用户需要的数据。

 

BLL:(业务逻辑层):UI层和DAL层之间的桥梁实现业务逻辑。业务逻辑具体包含:验证、计算、业务规则等等。

 

DAL:(数据访问层):与数据库打交道。主要实现对数据的增、删、改、查。将存储在数据库中的数据提交给业务层,同时将业务层处理的数据保存到数据库。(当然这些操作都是基于UI层的。用户的需求反映给界面(UI),UI反映给BLLBLL反映给DALDAL进行数据的操作,操作后再一一返回,直到将用户所需数据反馈给用户)

每一层都各负其责,那么该如何将三层联系起来呢?

1>单项引用(见下图)

2>这时候实体层(Entity)来了。(注:当然,实体层的作用不止这些)

 

Entity(实体层):它不属于三层中的任何一层,但是它是必不可少的一层。

Entity在三层架构中的作用(也叫模型层model):

1,实现面向对象思想中的"封装";

2,贯穿于三层,在三层之间传递数据;

注:确切的说实体层贯穿于三层之间,来连接三层)

3,对于初学者来说,可以这样理解:每张数据表对应一个实体,即每个数据表中的字段对应实体中的属性(注:当然,事实上不是这样。为什么?1>,可能我们需要的实体在数据表对应的实体中并不存在;2>,我们完全可以将所有数据表中的所有字段都放在一个实体里)

4,每一层(UI>BLL>DAL)之间的数据传递(单向)是靠变量或实体作为参数来传递的,这样就构造了三层之间的联系,完成了功能的实现。

但是对于大量的数据来说,用变量做参数有些复杂,因为参数量太多,容易搞混。比如:我要把员工信息传递到下层,信息包括:员工号、姓名、年龄、性别、工资....用变量做参数的话,那么我们的方法中的参数就会很多,极有可能在使用时,将参数匹配搞混。这时候,如果用实体做参数,就会很方便,不用考虑参数匹配的问题,用到实体中哪个属性拿来直接用就可以,很方便。这样做也提高了效率。(字段转成对象的属性)

注:这里为什么说可以暂时理解为每个数据表对应一个实体??答:大家都知道,我们做系统的目的,是为用户提供服务,用户可不关心你的系统后台是怎么工作的,用户只关心软件是不是好用,界面是不是符合自己心意。用户在界面上轻松的增、删、改、查,那么数据库中也要有相应的增、删、改、查,而增删改查具体操作对象就是数据库中的数据,说白了就是表中的字段。所以,将每个数据表作为一个实体类,实体类封装的属性对应到表中的字段,这样的话,实体在贯穿于三层之间时,就可以实现增删改查数据了)

思想来源于生活:

服务员:只管接待客人;

厨师:只管做客人点的菜;

采购员:只管按客人点菜的要求采购食材;

他们各负其职,服务员不用了解厨师如何做菜,不用了解采购员如何采购食材;厨师不用知道服务员接待了哪位客人,不用知道采购员如何采购食材;同样,采购员不用知道服务员接待了哪位客人,不用知道厨师如何做菜。

他们三者是如何联系的?

比如:厨师会做:炒茄子、炒鸡蛋、炒面——此时构建三个方法( cookEggplant()cookEgg()cookNoodle())

 

顾客直接和服务员打交道,顾客和服务员(UI层)说:我要一个炒茄子,而服务员不负责炒茄子,她就把请求往上递交,传递给厨师(BLL层),厨师需要茄子,就把请求往上递交,传递给采购员(DAL层),采购员从仓库里取来茄子传回给厨师,厨师响应cookEggplant()方法,做好炒茄子后,又传回给服务员,服务员把茄子呈现给顾客。

这样就完成了一个完整的操作。

在此过程中,茄子作为参数在三层中传递,如果顾客点炒鸡蛋,则鸡蛋作为参数(这是变量做参数)。如果,用户增加需求,我们还得在方法中添加参数,一个方法添加一个,一个方法设计到三层;何况实际中并不止设计到一个方法的更改。所以,为了解决这个问题,我们可以把茄子、鸡蛋、面条作为属性定义到顾客实体中,一旦顾客增加了炒鸡蛋需求,直接把鸡蛋属性拿出来用即可,不用再去考虑去每层的方法中添加参数了,更不用考虑参数的匹配问题。

这样讲,不知道大家是不是可以明白。(待会实例解释吧)

2,为什么使用三层?

使用三层架构的目的:解耦!!!

同样拿上面饭店的例子来讲:

1)服务员(UI层)请假——另找服务员;厨师(BLL层)辞职——招聘另一个厨师;采购员(DAL)辞职——招聘另一个采购员;

2)顾客反映:1>你们店服务态度不好——服务员的问题。开除服务员;

2>你们店菜里有虫子——厨师的问题。换厨师;

任何一层发生变化都不会影响到另外一层!!!

3,与两层的区别??

两层:

(当任何一个地方发生变化时,都需要重新开发整个系统。“多层”放在一层,分工不明确耦合度高——难以适应需求变化,可维护性低、可扩展性低)

三层:

(发生在哪一层的变化,只需更改该层,不需要更改整个系统。层次清晰,分工明确,每层之间耦合度低——提高了效率,适应需求变化,可维护性高,可扩展性高)

综上:三层架构的

优势:1,结构清晰、耦合度低,2,可维护性高,可扩展性高;3,利于开发任务同步进行;容易适应需求变化

劣势:1、降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。

2、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码

3、增加了代码量,增加了工作量

4,三层的具体表现形式??

models:定义用户实体模型

namespace WeatherStationManager.Models
{
   public class User
    {
        int userId;

        public int UserId
        {
            get { return userId; }
            set { userId = value; }
        }
        string userName;

        public string UserName
        {
            get { return userName; }
            set { userName = value; }
        }
        string userPassWord;

        public string UserPassWord
        {
            get { return userPassWord; }
            set { userPassWord = value; }
        }
        bool isDel;

        public bool IsDel
        {
            get { return isDel; }
            set { isDel = value; }
        }
        DateTime addTime;

        public DateTime AddTime
        {
            get { return addTime; }
            set { addTime = value; }
        }
    }
}

DAL:唯一直接与数据库交互的层

1创建数据库访问公共类,负责完成 数据库访问对象的建立,数据库连接建立,sql命令的执行方法

namespace WeatherStationManager.DAL
{
    public class DBHelpSQL
    {

        private SqlConnection conn;//创建一个sql数据库打开的连接,参数是连接字符串
        /// <summary>
        /// 数据库连接对象属性
        /// </summary>
        /// 
       
        public SqlConnection Conn//封装为属性
        {
            get
            {
              // string connectionString = ConfigurationManager.ConnectionStrings["ConnString"].ToString();
               string connectionString = "server=.;database=WeatherStation;uid=sa;pwd=sasasa";
                if (conn == null)
                {
                    conn = new SqlConnection(connectionString);
                    conn.Open();
                }
                else if (conn.State == System.Data.ConnectionState.Closed)
                {
                    conn.Open();
                }
                else if (conn.State == System.Data.ConnectionState.Broken)
                {
                    conn.Close();
                    conn.Open();
                }
                return conn;
            }
        }
        /// <summary>
        /// 关闭数据库连接
        /// </summary>
        public void CloseDB()
        {
            if (conn.State == System.Data.ConnectionState.Open || conn.State == System.Data.ConnectionState.Broken)
            {
                conn.Close();
            }
        }
// 创建sqlDataReader对象(每次向数据库只读一条)必须调用 SqlCommand 对象的 ExecuteReader 方法,read()方法读取 ,每次读一条数据 ,查询 语句
public SqlDataReader ExecuteReader(string sql, params SqlParameter[] parmaeters) { // SqlConnection conn = new SqlConnection(connctionString); SqlCommand cmd = new SqlCommand(sql, Conn); if (parmaeters != null) { cmd.Parameters.AddRange(parmaeters); } // conn.Open(); return cmd.ExecuteReader(CommandBehavior.CloseConnection);//返回sqlDataReader对象 } /// <summary> /// 执行sql语句 返回数据表 ,查询 /// </summary> /// <param name="safeSql">sql语句</param> /// <returns>数据表</returns> public DataTable GetDataTable(string safeSql) { //SqlConnection conn = new SqlConnection(connctionString); DataSet ds = new DataSet(); SqlCommand cmd = new SqlCommand(safeSql,Conn);
        //SqlDataAdapter是 DataSet和 SQL Server之间的桥接 SqlDataAdapter da
= new SqlDataAdapter(cmd);//SqlCommand是sql命令,执行后通过sqlDataAdapter返回填入DataSet, da.Fill(ds); return ds.Tables[0];//将dataset的第一张表返回也就是datatable ,因为dataset是数据表集合 ,相当于内存中的数据库 } /// <summary> /// 执行sql语句 返回数据表 , 查询语句 /// </summary> /// <param name="sql">sql语句</param> /// <param name="values">sql参数列表</param> /// <returns>数据表</returns> public DataTable GetDataTable(string sql, params SqlParameter[] values) { DataSet ds = new DataSet(); SqlCommand cmd = new SqlCommand(sql, Conn); cmd.Parameters.AddRange(values); SqlDataAdapter da = new SqlDataAdapter(cmd); da.Fill(ds); cmd.Parameters.Clear(); return ds.Tables[0]; } /// <summary> /// 执行Command , 执行增删改 /// </summary> /// <param name="sql">sql语句</param> /// <param name="values">sql参数数组</param> /// <returns></returns> public int ExecuteCommand(string sql, params SqlParameter[] values) { SqlCommand cmd = new SqlCommand(sql, Conn); cmd.Parameters.AddRange(values); int result = cmd.ExecuteNonQuery(); //执行(增删改)的方法,返回执行命令所影响的行数(return int类型) cmd.Parameters.Clear(); return result; } /// <summary> /// 执行带sql参数的语句 /// </summary> /// <param name="sql">sql语句</param> /// <param name="values">sql参数列表</param> /// <returns></returns> public int GetScalar(string sql, params SqlParameter[] values) { object obj = null; try { SqlCommand cmd = new SqlCommand(sql, Conn); cmd.Parameters.AddRange(values); obj = cmd.ExecuteScalar();//获得查询到的结果集的第一个单元格的值,为obj类型 cmd.Parameters.Clear(); } catch (Exception ex) { throw ex; } finally { CloseDB(); } if (obj == null) return 0; else return Convert.ToInt32(obj); } } }

 2增删改查

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

using WeatherStationManager.Models;
using System.Data.SqlClient;
using System.Data;
using System.Reflection;

namespace WeatherStationManager.DAL
{
    public class UserServices
    {
        DBHelpSQL dbHelper = null;  //DAL层需要用到数据库访问公共类 ,这里建立dbhelp对象
        public UserServices()
        {
            dbHelper = new DBHelpSQL();
        }
  
        #region 修改
        /// <summary>
        /// 修改学员信息
        /// </summary>
        /// <param name="model">学员实体</param>
        /// <returns></returns>
        public bool ModifyStudent(Models.User model)
        {
            StringBuilder sbSql = new StringBuilder("update [User] set ");// user 与系统关键字冲突  用[] 括起来
            Type modeType = model.GetType();//获得对象的类型
            PropertyInfo[] pros = modeType.GetProperties(); // 得到类型的所有公共属性
            List<SqlParameter> paras = new List<SqlParameter>();
            foreach (PropertyInfo pi in pros)   //反射获得属性和属性的值
            {
                if (!pi.Name.Equals("UserId") && !pi.Name.Contains("AddTime"))//如果不是主键则追加sql字符串
                {
                    if (pi.GetValue(model, null) != null && !pi.GetValue(model, null).ToString().Equals(""))//判断属性值是否为空
                    {
                        sbSql.Append(pi.Name + "=@" + pi.Name + ",");//SID=@SID
                        paras.Add(new SqlParameter("@" + pi.Name, pi.GetValue(model, null)));
                    }
                }
            }
            string strSql = sbSql.ToString().Trim(','); //去掉两边的,
            strSql += " where UserId=@UserId";
            paras.Add(new SqlParameter("@UserId", model.UserId));
            return dbHelper.ExecuteCommand(strSql, paras.ToArray()) > 0;   //执行语句
        }
        #endregion
        #region 修改密码
        /// <summary>
        /// 修改学员信息
        /// </summary>
        /// <param name="model">学员实体</param>
        /// <returns></returns>
        public bool ModifyPwd(Models.User model)
        {
            string Sql = "update [User] set UserPassWord=@userpwd where UserName=@username ";
            Type modeType = model.GetType();
            SqlParameter[] parms = {
                                       new SqlParameter("@username",model.UserName),
                                       new SqlParameter("@userpwd",model.UserPassWord) 
                                   };
            return dbHelper.ExecuteCommand(Sql, parms) > 0;
        }
        #endregion

        #region 根据查询条件 返回 学生实体 列表  ,查询 
        /// <summary>
        /// 根据查询条件 返回 学生实体 列表 where SName=@SName and SPwd=@SPwd and SPwd=@SPwd
        /// </summary>
        /// <returns></returns>
        public List<Models.User> QueryListByCondition(SqlParameter[] paras)
        {
            Models.User model = null;
            StringBuilder sbSql = new StringBuilder("select * from [User]  where IsDel=0 ");
            if (paras != null)//如果参数数组不为空,则循环生成sql的条件语句,追加查询条件
            {
                for (int i = 0; i < paras.Length; i++)//循环所有参数(如: and PWD=@SPWD)
                {
                    SqlParameter p = paras[i];
                    sbSql.Append(" and ");//第二个参数开始 在前面加 and
                    sbSql.Append(p.ParameterName.Substring(1));//获得参数所对应的列名
                    sbSql.Append("=" + p.ParameterName);
                }
            }
            //读取数据库 返回查询到的数据表(如果参数为null,则直接执行sql语句,否则带参数执行sql语句)
            DataTable dt = (paras == null) ? dbHelper.GetDataTable(sbSql.ToString()) : dbHelper.GetDataTable(sbSql.ToString(), paras);
            //准备要返回的泛型集合
            List<Models.User> list = null;
            if (dt.Rows.Count > 0)//如果查询到的行数大于0
            {
                list = new List<Models.User>();//实例化集合对象
                foreach (DataRow dr in dt.Rows)//循环临时表的行记录
                {
                    model = new Models.User();//每循环一行生成一个实体
                    SetDr2Model(dr, model);//将行数据填入实体对应的属性
                    list.Add(model);//将实体对象加入集合
                }
            }
            return list;
        }
        #endregion
        #region 新增
        public int ADD(Models.User MOD)
        {
            string sql = "insert into [User] (UserName,UserPassWord) values (@UserName,@UserPassWord);select @@identity";
              //insert into 后获得自动插入的id(select @@identity) SqlParameter[] pars
={ new SqlParameter("@UserName",MOD.UserName), new SqlParameter("@UserPassWord",MOD.UserPassWord) }; int res = dbHelper.GetScalar(sql, pars); //获得插入id return res; } #endregion #region 根据id删除指定行 public int DelById(string UserId) { int res = dbHelper.ExecuteCommand("delete [User] where UserId=@UserId", new SqlParameter("@UserId", UserId)); return res; } #endregion #region 返回单个学生实体 public User GetUserByCondition(string UserName, string UserPwd) { string sql = "select * from [User] where UserName=@username and UserPassWord=@userpwd"; SqlParameter[] parms = { new SqlParameter("@username",UserName), new SqlParameter("@userpwd",UserPwd) }; SqlDataReader dr = dbHelper.ExecuteReader(sql, parms); User oneUser = null; //转换成实体对象 if (dr.Read()) { oneUser = new User(); oneUser.UserId = Convert.ToInt32(dr["UserId"]); oneUser.UserName = dr["UserName"].ToString(); oneUser.UserPassWord = dr["UserPassWord"].ToString(); oneUser.IsDel = Convert.ToBoolean(dr["IsDel"]); oneUser.AddTime = Convert.ToDateTime(dr["AddTime"]); } dr.Close();// dataReader 用完一定要关闭 return oneUser; } #endregion #region 将 数据行 转换 成 实体对象 /// <summary> /// 将 数据行 转换 成 实体对象,用于将dataset 的每一行转成实体对象 /// </summary> /// <param name="dr">数据行</param> /// <param name="model">实体对象</param> public void SetDr2Model(DataRow dr, Models.User model) { if (dr["UserId"].ToString() != "") { model.UserId = int.Parse(dr["UserId"].ToString()); } if (dr["UserName"].ToString() != "") { model.UserName = dr["UserName"].ToString(); } model.UserPassWord = dr["UserPassWord"].ToString(); if (dr["IsDel"].ToString() != "") { model.IsDel = bool.Parse(dr["IsDel"].ToString()); } if (dr["AddTime"].ToString() != "") { model.AddTime = DateTime.Parse(dr["AddTime"].ToString()); } } #endregion } }

 BLL:UI层与DAL层交互的桥梁

namespace WeatherStationManager.BLL
{
    public class UserManager
    {
        UserServices userServices = new UserServices();  //BLL层只需要与DAL层交互 ,这里建立 DAL层的对象
    /*    public int AddUser(User addUser)
        {
            if (!this.CheckExists(addUser.UserName,addUser.UserPassWord))
            {
                //返回false表示不存在,则新增
                return userServices.AddUser(addUser);
            }
            else
            {
                throw new Exception("用户名已存在!");
            }
        }*/
        #region 修改密码
        /// <summary>
        /// 修改学员信息
        /// </summary>
        /// <param name="model">学员实体</param>
        /// <returns></returns>
        public bool ModifyPwd(Models.User model)
        {
           return userServices.ModifyPwd(model);
        }
        #endregion
        #region del
        public bool DelById(string UserId)
        {
            int res = userServices.DelById(UserId);
            bool resBool = false;
            if (res > 0)
                resBool = true;
            else resBool = false;
            return resBool;
        }  
        #endregion
        #region add
        public bool ADD(Models.User mod)
        {
            int newId = userServices.ADD(mod);
            return newId > 0;
        } 
        #endregion
        #region updata
        /// <summary>
        /// 修改学员信息
        /// </summary>
        /// <param name="model">学员实体</param>
        /// <returns></returns>
        public bool ModifyStudent(Models.User model)
        {
            return userServices.ModifyStudent(model);
        }
        #endregion
        #region 获得所有user
        /// <summary>
        /// 获得所有列表
        /// </summary>
        /// <returns></returns>
        public List<Models.User> GetAllUsers()
        {
            return userServices.QueryListByCondition(null);
        }
        #endregion
        #region 是否存在

        /// <summary>
        /// 检测userName在数据库中是否存在,如果存在返回true,否则返回false
        /// </summary>
        /// <param name="typeName"></param>
        /// <returns></returns>
        public bool CheckExists(string userName, string userPwd)
        {
            User oneUser = userServices.GetUserByCondition(userName, userPwd);
            if (oneUser != null)
            {
                return true;
            }
            else
            {
                return false;
            }
        } 
        #endregion
    }
}

我这里由于业务比较简单,其实必要的话 ,业务逻辑层是会加上一些复杂的逻辑判断的。

这样的分层  数据层 只是访问 数据库 , 业务层做一些逻辑判断 , UI层负责显示 与输入 

UI层 : 用户交互 

 1                 string uName = tb1.Text;  //获取用户输入
 2                 string uPwd = tb2.Text;
 3                 string apwd = tb3.Text;
 4                 bool res = false;
 5                 UserManager userManager = new UserManager();  //由于UI层只需要与BLL层交互 ,这里建立BLL对象
 6                 Models.User model=new Models.User();
 7                 if (uPwd!=apwd)
 8                 {
 9                     Response.Write("<script>alert('两次输入的密码不一致!')</script>");
10                 }
11                 else
12                 {
13                     model.UserName = uName;
14                     model.UserPassWord = uPwd;
15                     res = userManager.ModifyPwd(model);
16                     Response.Write("<script>alert('修改成功!')</script>");
17                 }
原文地址:https://www.cnblogs.com/wangjian920110/p/5454969.html