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("不存在该记录!");
}
}
}
}


说点什么
欢迎讨论