1.各层的作用?
数据访问层(DAL层):主要是对原始数据(数据库或者文本文件等存放数据的形式)的操作层,是对数据的操作,具体为业务逻辑层或表示层提供数据服务。
业务逻辑层(BLL层):主要是针对具体的问题的操作,,对数据业务逻辑处理,或者理解成对数据层的操作。
表示层(UI层):主要表示WEB方式,也可以表示成WINFORM方式,WEB方式也可以表现成:aspx, 作为展示。
2.为什么要分三层?
答:使项目结构更清楚,分工更明确,有利于后期的维护和升级。它未必会提升性能,核心就是:修改表现层而不用修改逻辑层,修改逻辑层而不用修改数据层,有很多复杂的三层架构和多层架构,这里只做基本的三层架构描述。
好处: 分工合作,开发人员可以专注于某一层;可移植性、模块化设计、重用性;支持分布式系统(基于网络)扩展性强; MSSQL、Oracle之间可以切换。
接下来用话术脚本的例子做一下简单三层描述:
话术脚本:又叫知识库,坐着对着电脑念给客户的东西,比如移动客户人员回答客户来电时用的一种文件。如图:
开发步骤(顺序可变):
1)设计数据库表(DB);
2)设计取得各级数据的方法(DAL层);
3)设计界面,将表中的数据加载到TreeView中,为了能够在点击节点的时候将节点的正文填充到文本框中,因此将每个节点对应的Model 放到节点的Tag中(UI层)。
4)设计话术的添加、删除、修改、查找等功能(BLL业务逻辑层)。
Model层:
public class T_Script { public int ScriptId { get; set; } public string ScriptTitle { get; set; } public string ScriptMsg { get; set; } public int ScriptParentId { get; set; } }
Dal层(需SqlHelper.cs):
public class T_ScriptsDal { //选中类别显示该id的所有内容 public T_Script GetScriptModelByScriptId(int sid) { T_Script model = null; string sql = "select * from T_Scripts where ScriptId=@sid"; using (SqlDataReader reader = SqlHelper.ExecuteReader(sql, System.Data.CommandType.Text, new SqlParameter("@sid", sid))) { if (reader.HasRows) { if (reader.Read()) { model = new T_Script(); model.ScriptId = reader.GetInt32(0); model.ScriptTitle = reader.GetString(1); model.ScriptMsg = reader.GetString(2); model.ScriptParentId = reader.GetInt32(3); } } } return model; } //根据id获取数据库中的话术信息,供之后加载到treeview上 public List<T_Script> GetScriptsByParentId(int pid) { List<T_Script> list = new List<T_Script>(); string sql = "select ScriptId,ScriptTitle from T_Scripts where ScriptParentId=@pid"; using (SqlDataReader reader = SqlHelper.ExecuteReader(sql, System.Data.CommandType.Text, new SqlParameter("@pid", pid))) { if (reader.HasRows) { while (reader.Read()) { T_Script model = new T_Script(); model.ScriptId = reader.GetInt32(0); model.ScriptTitle = reader.GetString(1); list.Add(model); } } } return list; } //根据ScriptId查询Message:查询功能 public string GetScriptMessageByScriptId(int sid) { string sql = "select ScriptMsg from T_Scripts where ScriptId=@sid"; object obj = SqlHelper.ExecuteScalar(sql, System.Data.CommandType.Text, new SqlParameter("@sid", sid)); return obj == null ? string.Empty : obj.ToString(); } //添加功能 public int Insert(T_Script model) { string sql = "insert into T_Scripts(ScriptTitle,ScriptMsg,ScriptParentId) values(@title,@msg,@pid)"; SqlParameter[] pms = new SqlParameter[] { new SqlParameter("@title",model.ScriptTitle), new SqlParameter("@msg",model.ScriptMsg), new SqlParameter("@pid",model.ScriptParentId) }; return SqlHelper.ExecuteNonQuery(sql, System.Data.CommandType.Text, pms); } //删除功能 public int DeleteByScriptId(int sid) { string sql = "delete from T_Scripts where ScriptId=@sid"; return SqlHelper.ExecuteNonQuery(sql, System.Data.CommandType.Text, new SqlParameter("@sid", sid)); } //编辑修改功能 public int Update(T_Script model) { string sql = "update T_Scripts set ScriptTitle=@title,ScriptMsg=@msg where ScriptId=@sid"; SqlParameter[] pms = new SqlParameter[] { new SqlParameter("@title",model.ScriptTitle), new SqlParameter("@msg",model.ScriptMsg), new SqlParameter("@sid",model.ScriptId) }; return SqlHelper.ExecuteNonQuery(sql, System.Data.CommandType.Text, pms); } } }
SqlHelper.cs
public static class SqlHelper { private static string conStr = ConfigurationManager.ConnectionStrings["coco"].ConnectionString; //增删改 public static int ExecuteNonQuery(string sqlStr, CommandType ct, params SqlParameter[] sq) { using (SqlConnection sqlCon = new SqlConnection(conStr)) { using (SqlCommand cmd = new SqlCommand(sqlStr, sqlCon)) { cmd.CommandType = ct; if (sq != null) { cmd.Parameters.AddRange(sq); } //打开连接 sqlCon.Open(); return cmd.ExecuteNonQuery(); } } } //scalar public static object ExecuteScalar(string sqlStr, CommandType ct, params SqlParameter[] sq) { using (SqlConnection sqlCon = new SqlConnection(conStr)) { using (SqlCommand cmd = new SqlCommand(sqlStr, sqlCon)) { cmd.CommandType = ct; if (sq != null) { cmd.Parameters.AddRange(sq); } //打开连接 sqlCon.Open(); return cmd.ExecuteScalar(); } } } //reader public static SqlDataReader ExecuteReader(string sqlStr, CommandType ct, params SqlParameter[] sq) { SqlConnection sqlCon = new SqlConnection(conStr); using (SqlCommand cmd = new SqlCommand(sqlStr, sqlCon)) { cmd.CommandType = ct; if (sq != null) { cmd.Parameters.AddRange(sq); } //打开连接 try { sqlCon.Open(); return cmd.ExecuteReader(CommandBehavior.CloseConnection); } catch (Exception) { sqlCon.Dispose(); throw; } } } //table public static DataTable ExecuteDataTable(string sqlStr, CommandType ct, params SqlParameter[] sq) { DataTable dt = new DataTable(); using (SqlDataAdapter sda=new SqlDataAdapter(sqlStr,conStr)) { sda.SelectCommand.CommandType = ct; if (sq != null) { sda.SelectCommand.Parameters.AddRange(sq); } sda.Fill(dt); return dt; } } } }
BLL层:
public class T_ScriptsBll { //引用Dal层并创建对象,开始业务逻辑层描述。 T_ScriptsDal dal = new T_ScriptsDal(); //根据id获取数据库中的话术信息,供UI层之后加载到treeview上 public List<T_Script> GetScriptsByParentId(int pid) { return dal.GetScriptsByParentId(pid); } //根据ScriptId查询Message:查询功能 public string GetScriptMessageByScriptId(int sid) { return dal.GetScriptMessageByScriptId(sid); } //添加功能 public int Insert(T_Script model) { return dal.Insert(model); } //根据ScriptId删除一条记录:删除功能 public int DeleteByScriptId(int sid) { return dal.DeleteByScriptId(sid); } //递归删除 public void DiguiDeleteByScriptId(int sid) { //1.根据sid查询,并遍历 List<T_Script> list = GetScriptsByParentId(sid); foreach (T_Script item in list) { DiguiDeleteByScriptId(item.ScriptId); } //2.删除当前的sid DeleteByScriptId(sid); } //编辑修改功能 public int Update(T_Script model) { return dal.Update(model); } //创建model:选中类别显示该id的所有内容 public T_Script GetScriptModelByScriptId(int sid) { return dal.GetScriptModelByScriptId(sid); } } }
UI层:
父窗口:
public partial class frmScripts : Form { public frmScripts() { InitializeComponent(); } private void UpdateEditNode(string title, string message) { if (treeView1.SelectedNode != null) { treeView1.SelectedNode.Text = title; txtMessage.Text = message; } } //窗体加载事件:委托 private void frmScripts_Load(object sender, EventArgs e) { RefreshTreeView(); } private void RefreshTreeView() { treeView1.Nodes.Clear(); //加载类别到TreeView LoadScriptTitleToTree(0, treeView1.Nodes); } //引用BLL层,并创建对象 T_ScriptsBll bll = new T_ScriptsBll(); //查询后加载 private void LoadScriptTitleToTree(int pid, TreeNodeCollection treeNodeCollection) { //1.根据pid查询数据 List<T_Script> list = bll.GetScriptsByParentId(pid); //2.把查询到的数据绑定到treeNodeCollection集合中 foreach (var itemScript in list) { TreeNode tnode = treeNodeCollection.Add(itemScript.ScriptTitle); tnode.Tag = itemScript.ScriptId; //递归 LoadScriptTitleToTree(itemScript.ScriptId, tnode.Nodes); } } //TreeView的节点的选中后触发的事件 private void treeView1_AfterSelect(object sender, TreeViewEventArgs e) { //1.获取选中节点 if (e.Node != null) { //2.获取选中个节点中的ScriptId int scriptId = (int)e.Node.Tag; //3.根据ScriptId查询对应的ScriptMsg T_ScriptsBll bll = new T_ScriptsBll(); //4.将查询到的ScriptMsg赋值给右侧的文本框 txtMessage.Text = bll.GetScriptMessageByScriptId(scriptId); } } //添加功能:1 private void 增加一级类别ToolStripMenuItem_Click(object sender, EventArgs e) { frmAddScripts frmScripts = new frmAddScripts(RefreshTreeView, 0); frmScripts.Show(); } //添加功能:2 private void 在选中的类别下增加子类别ToolStripMenuItem_Click(object sender, EventArgs e) { if (treeView1.SelectedNode != null) { frmAddScripts frmScripts = new frmAddScripts(RefreshTreeView, (int)treeView1.SelectedNode.Tag); frmScripts.Show(); } else { MessageBox.Show("请选中节点!"); } } //删除功能:删除选中的TreeView节点 private void 删除选中类别ToolStripMenuItem_Click(object sender, EventArgs e) { if (treeView1.SelectedNode != null) { int sid = (int)treeView1.SelectedNode.Tag; //执行删除 T_ScriptsBll bll = new T_ScriptsBll(); bll.DiguiDeleteByScriptId(sid); //从界面上删除 treeView1.SelectedNode.Remove(); } } //编辑修改功能 private void 编辑ToolStripMenuItem_Click(object sender, EventArgs e) { //1.先判断是否有选中节点 if (treeView1.SelectedNode != null) { int sid = (int)treeView1.SelectedNode.Tag; //显示编辑窗口 frmScriptEdit frmEdit = new frmScriptEdit(sid, UpdateEditNode); frmEdit.Show(); } else { MessageBox.Show("请选中节点!"); } } //搜索功能:展示 //在TreeView上进行节点搜索 private void tsmiSearchBtn_Click(object sender, EventArgs e) { //将TreeView的所有节点都合上。 treeView1.CollapseAll(); string search = tsTextSearch.Text.Trim(); //递归搜索节点 SearchNodeText(search, treeView1.Nodes); } //搜索功能 private void SearchNodeText(string search, TreeNodeCollection treeNodeCollection) { foreach (TreeNode item in treeNodeCollection) { if (item.Text.Contains(search)) { item.BackColor = Color.Red; //确保当前节点可见。用户可以看得到,其实就是把相关的父节点都展开。 item.EnsureVisible(); } else { item.BackColor = Color.White; } //递归搜索 SearchNodeText(search, item.Nodes); } } } }
子窗口:增加功能
public partial class frmAddScripts : Form { //增加功能:子窗口 public frmAddScripts() { InitializeComponent(); } //委托传递:保证子窗口添加后,父窗口可以同时刷新treeview同步显示增加后结果 public frmAddScripts(Action method, int pid) : this() { this._refreshTree = method; this._parentId = pid; } private int _parentId; //定义无参数无返回值的委托 private Action _refreshTree; //增加的按钮事件: private void button1_Click(object sender, EventArgs e) { //1.采集数据 T_Script model = new T_Script(); model.ScriptTitle = txtTitle.Text.Trim(); model.ScriptMsg = txtMessage.Text.Trim(); model.ScriptParentId = _parentId; //2.调用业务逻辑层实现增加一条话术脚本 T_ScriptsBll bll = new T_ScriptsBll(); bll.Insert(model); if (_refreshTree != null) { //刷新父窗口中的TreeView _refreshTree(); } this.Close(); } } }
子窗口:编辑修改
public partial class frmScriptEdit : Form { private int sid; //编辑修改功能:子窗口 public frmScriptEdit() { InitializeComponent(); } //委托传递 public frmScriptEdit(int sid, Action<string, string> method) : this() { // TODO: Complete member initialization this.sid = sid; _updateNode = method; } //定义委托:有两个参数 private Action<string, string> _updateNode; //执行更新操作 private void button1_Click(object sender, EventArgs e) { //1.采集数据 T_Script model = new T_Script(); model.ScriptId = this.sid; model.ScriptTitle = txtTitle.Text.Trim(); model.ScriptMsg = txtMessage.Text.Trim(); //2.调用业务逻辑层执行更新操作 T_ScriptsBll bll = new T_ScriptsBll(); bll.Update(model); if (_updateNode != null) { //通过委托更新主窗口中的TreeView节点。 _updateNode(model.ScriptTitle, model.ScriptMsg); } this.Close(); } //窗体加载 private void frmScriptEdit_Load(object sender, EventArgs e) { //现根据要更新的记录的sid,获取该记录的最新的内容填充到文本框中 LoadEditInfo(); } private void LoadEditInfo() { T_ScriptsBll bll = new T_ScriptsBll(); T_Script model = bll.GetScriptModelByScriptId(this.sid); if (model != null) { this.txtTitle.Text = model.ScriptTitle; this.txtMessage.Text = model.ScriptMsg; } else { throw new Exception("不存在该记录!"); } } } }
说点什么
欢迎讨论