C#01-三層架構-影院系統零食銷售示例
一、三層架構
1、三層架構是什麼?
通常意義上的三層架構就是將整個業務應用劃分爲:
表現層(UI)、業務邏輯層(BLL)、數據訪問層(DAL)。
區分層次的目的即爲了“高內聚,低耦合”的思想。
表現層(UI):通俗講就是展現給用戶的界面,即用戶在使用一個系統的時候的所見所得。
業務邏輯層(BLL):針對具體問題的操作,也可以說是對數據層的操作,對數據業務邏輯處理。
數據訪問層(DAL):該層所做事務直接操作數據庫,針對數據的增添、刪除、修改、更新、查找等每層之間是一種垂直的關係。
2、優缺點
優點: 分工明確,條理清晰,易於調試,而且具有可擴展性。
缺點: 增加成本。
3、調用關係
DAL、BLL、UI、Model(模型層)、Common(通用層)
調用關係:
DAL層調用Model層,Common層
BLL層調用DAL層、Model層、Common層
UI層調用BLL層、Model層、Common層
例如影院系統零食銷售示例中,我創建瞭如上圖介紹的五個類庫(其中COMMON可以不創建,例子中沒有用到,其餘四個類庫內容在下文展開詳細敘述)
4、開發順序
開發順序:DAL->BLL->UI 翻過來也可以
二、影院系統零食銷售示例
1.創建數據庫
(用的SQL Server)首先創建一個叫 movie 的數據庫,接着創建Snacks(零食)和SnacksType(零食分類)兩張表。
上代碼哈哈哈(也可以手動創建):
USE [movie]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Snacks](
[SId] [int] IDENTITY(1,1) NOT NULL,
[STitle] [varchar](50) NOT NULL,
[SPrice] [decimal](5, 2) NOT NULL,
[STypeId] [int] NOT NULL,
[SIsDelete] [int] NOT NULL,
CONSTRAINT [PK_Snacks] PRIMARY KEY CLUSTERED
(
[SId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[SnacksType](
[SId] [int] IDENTITY(1,1) NOT NULL,
[STitle] [varchar](10) NOT NULL,
[SIsDelete] [int] NOT NULL
) ON [PRIMARY]
GO
添加數據:
SET IDENTITY_INSERT [dbo].[Snacks] ON
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (1, N'可比克', CAST(15.00 AS Decimal(5, 2)), 1, 0)
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (2, N'手指餅', CAST(7.50 AS Decimal(5, 2)), 1, 0)
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (3, N'番茄雞味塊', CAST(7.50 AS Decimal(5, 2)), 1, 0)
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (4, N'可樂', CAST(4.00 AS Decimal(5, 2)), 2, 0)
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (5, N'雪碧', CAST(4.00 AS Decimal(5, 2)), 2, 0)
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (6, N'橙汁', CAST(8.00 AS Decimal(5, 2)), 2, 0)
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (7, N'西瓜汁', CAST(8.00 AS Decimal(5, 2)), 2, 0)
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (8, N'奶茶', CAST(8.00 AS Decimal(5, 2)), 2, 0)
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (9, N'爆米花中份', CAST(10.00 AS Decimal(5, 2)), 3, 0)
INSERT [dbo].[Snacks] ([SId], [STitle], [SPrice], [STypeId], [SIsDelete]) VALUES (10, N'爆米花大份', CAST(15.00 AS Decimal(5, 2)), 3, 0)
SET IDENTITY_INSERT [dbo].[Snacks] OFF
SET IDENTITY_INSERT [dbo].[SnacksType] ON
INSERT [dbo].[SnacksType] ([SId], [STitle], [SIsDelete]) VALUES (1, N'零食', 0)
INSERT [dbo].[SnacksType] ([SId], [STitle], [SIsDelete]) VALUES (2, N'飲料', 0)
SET IDENTITY_INSERT [dbo].[SnacksType] OFF
2.1 模型類(MODEL)
零食類 Snacks:
namespace MODEL
{
public class Snacks
{
//--[SId], [STitle], [SPrice], [STypeId], [SIsDelete]
public string SId {
get; set; }
public string STitle {
get; set; }
public string SPrice {
get; set; }
public string STypeId {
get; set; }
public string SIsDelete {
get; set; }
public string STypeTitle {
get; set; }
public Snacks() {
}
}
}
零食分類類 SnacksType:
namespace MODEL
{
public class SnacksType
{
//--[SId], [STitle], [SIsDelete]
public string SId {
get; set; }
public string STitle {
get; set; }
public string SIsDelete {
get; set; }
public SnacksType() {
}
}
}
2.2 SqlHelper
3.1 數據訪問層(DAL)
數據訪問層里加了一個類SqlHelper,幫助操作數據庫。
SqlHelper:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
namespace DAL
{
public class SqlHelper
{
private static string connStr = "Data Source=.;Initial Catalog=movie;Integrated Security=True";
//增、刪、改
/// <summary>
/// 執行增、刪、改 的sql語句,返回受影響的行數
/// </summary>
/// <param name="sql">要執行的命令</param>
/// <param name="ps">命令中的參數</param>
/// <returns>受影響的行數</returns>
public static int ExecuteNonQuery(string sql, SqlParameter[] ps)
{
using (SqlConnection conn = new SqlConnection(connStr))
{
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
cmd.Parameters.AddRange(ps);
return cmd.ExecuteNonQuery();
}
}
}
/// <summary>
/// 執行增、刪、改 的sql語句,返回受影響的行數
/// </summary>
/// <param name="sql">要執行的命令</param>
/// <param name="ps">命令中的參數</param>
/// <returns>受影響的行數</returns>
public static int ExecuteNonQuery(string sql)
{
using (SqlConnection conn = new SqlConnection(connStr))
{
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
conn.Open();
return cmd.ExecuteNonQuery();
}
}
}
//查詢
public static DataTable getDataTable(string sql, SqlParameter[] ps)
{
using (SqlConnection conn = new SqlConnection(connStr))
{
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
DataTable dt = new DataTable();
cmd.Parameters.AddRange(ps);
sda.Fill(dt);
return dt;
}
}
}
}
public static DataTable getDataTable(string sql)
{
using (SqlConnection conn = new SqlConnection(connStr))
{
using (SqlCommand cmd = new SqlCommand(sql, conn))
{
using (SqlDataAdapter sda = new SqlDataAdapter(cmd))
{
DataTable dt = new DataTable();
sda.Fill(dt);
return dt;
}
}
}
}
}
}
零食 SnacksDAL:
using MODEL;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
namespace DAL
{
public class SnacksDAL
{
//刪除
public int delete(string sid)
{
string sql = "update Snacks set SIsDelete=1 where SId=@SId";
SqlParameter[] ps =
{
new SqlParameter("@SId",sid)
};
return SqlHelper.ExecuteNonQuery(sql, ps);
}
//修改
public int update(Snacks s)
{
string sql = "update Snacks set STitle=@STitle,Sprice=@Sprice,STypeId=@STypeId where SId=@SId";
SqlParameter[] ps =
{
new SqlParameter("@Stitle",s.STitle),
new SqlParameter("@Sprice",s.SPrice),
new SqlParameter("@STypeId",s.STypeId),
new SqlParameter("@SId",s.SId)
};
return SqlHelper.ExecuteNonQuery(sql, ps);
}
//新增
public int add(Snacks s)
{
string sql = "insert into Snacks(STitle,Sprice,STypeId)values(@STitle,@Sprice,@STypeId)";
SqlParameter[] ps =
{
new SqlParameter("@STitle",s.STitle),
new SqlParameter("@Sprice",s.SPrice),
new SqlParameter("@STypeId",s.STypeId)
};
return SqlHelper.ExecuteNonQuery(sql, ps);
}
//查詢顯示
public DataTable getList(Dictionary<string, string> dic)
{
List<SqlParameter> paraList = new List<SqlParameter>();
string sql = "select s.SId,s.STitle,st.STitle STypeTitle,SPrice from Snacks s,SnacksType st where s.STypeId=st.SId and s.SIsDelete=0";
if (dic.Count > 0)
{
foreach (KeyValuePair<string, string> kv in dic)
{
sql += " and s." + kv.Key + " like @" + kv.Key;
string pname = "@" + kv.Key;
string pvalue = "%" + kv.Value + "%";
paraList.Add(new SqlParameter(pname, pvalue));
}
}
return SqlHelper.getDataTable(sql, paraList.ToArray());
}
}
}
零食分類 SnacksTypeDAL:
using MODEL;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Text;
namespace DAL
{
public class SnacksTypeDAL
{
//刪除
public int delete(string sid)
{
string sql = "delete from SnacksType where SId=@SId";
SqlParameter[] ps =
{
new SqlParameter("@SId",sid)
};
return SqlHelper.ExecuteNonQuery(sql, ps);
}
//修改
public int update(SnacksType s)
{
string sql = "update SnacksType set STitle=@STitle where SId=@SId";
SqlParameter[] ps =
{
new SqlParameter("@STitle",s.STitle),
new SqlParameter("@SId",s.SId)
};
return SqlHelper.ExecuteNonQuery(sql, ps);
}
//添加
public int add(SnacksType s)
{
string sql = "insert into SnacksType(STitle)values(@STitle)";
SqlParameter[] ps =
{
new SqlParameter("@STitle",s.STitle)
};
return SqlHelper.ExecuteNonQuery(sql, ps);
}
//查詢顯示
public DataTable getList()
{
string sql = "select SId,STitle from SnacksType";
return SqlHelper.getDataTable(sql);
}
}
}
3.2 業務邏輯層(BLL)
零食 SnacksBLL:
using DAL;
using MODEL;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace BLL
{
public class SnacksBLL
{
SnacksDAL dal = new SnacksDAL();
//刪除
public bool delete(string sid)
{
return dal.delete(sid) > 0;
}
//修改
public bool update(Snacks s)
{
return dal.update(s) > 0;
}
//添加
public bool add(Snacks s)
{
return dal.add(s) > 0;
}
//查詢顯示
public List<Snacks> getList(Dictionary<string, string> dic)
{
List<Snacks> list = new List<Snacks>();
DataTable dt = dal.getList(dic);
foreach (DataRow row in dt.Rows)
{
Snacks s = new Snacks();
s.SId = row["SId"].ToString();
s.STitle = row["STitle"].ToString();
s.SPrice = row["SPrice"].ToString();
s.STypeId = row["STypeTitle"].ToString();
list.Add(s);
}
return list;
}
}
}
零食分類 SnacksTypeBLL:
using DAL;
using MODEL;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
namespace BLL
{
public class SnacksTypeBLL
{
SnacksTypeDAL dal = new SnacksTypeDAL();
//刪除
public bool delete(string sid)
{
return dal.delete(sid) > 0;
}
//修改
public bool update(SnacksType s)
{
return dal.update(s) > 0;
}
//添加
public bool add(SnacksType s)
{
return dal.add(s) > 0;
}
//查詢顯示
public List<SnacksType> getList()
{
List<SnacksType> list = new List<SnacksType>();
DataTable dt = dal.getList();
foreach (DataRow row in dt.Rows)
{
SnacksType t = new SnacksType();
t.SId = row["SId"].ToString();
t.STitle = row["STitle"].ToString();
list.Add(t);
}
return list;
}
}
}
3.3表現層(UI)
這是我畫的零食界面:
事件代碼:
using BLL;
using MODEL;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace UI
{
public partial class FormSnacks : Form
{
public FormSnacks()
{
InitializeComponent();
}
SnacksBLL bll = new SnacksBLL();
//拼接模糊查詢條件
private void loadList()
{
Dictionary<string, string> dic = new Dictionary<string, string>();
string titleSearch = txtTitleSearch.Text.Trim();
string typesearch = ddlTypeSearch.SelectedValue.ToString();
//MessageBox.Show(typesearch);
//創建泛型鍵值對集合、用於存儲SQL語句中模糊查詢的條件
if (txtTitleSearch.Text != "")
{
dic.Add("STitle", txtTitleSearch.Text);
}
if (typesearch != "0")
{
dic.Add("STypeId", typesearch);
}
dgvList.AutoGenerateColumns = false;
dgvList.DataSource = bll.getList(dic);
}
//分類搜索下拉框
private void loadSearchTypeList()
{
SnacksTypeBLL stbll = new SnacksTypeBLL();
List<SnacksType> list = stbll.getList();
SnacksType st = new SnacksType();
st.SId = "0";
st.STitle = "全部";
// list.Add(st);
list.Insert(0, st);
//綁定數據
ddlTypeSearch.DisplayMember = "STitle";
ddlTypeSearch.ValueMember = "SId";
ddlTypeSearch.DataSource = list;
}
//增加/修改分類下拉框
private void loadAddTypeList()
{
SnacksTypeBLL stbll = new SnacksTypeBLL();
List<SnacksType> list = stbll.getList();
SnacksType st = new SnacksType();
st.SId = "0";
st.STitle = "全部";
// list.Add(st);
list.Insert(0, st);
//SId,STitle
ddlTypeAdd.DisplayMember = "STitle";
ddlTypeAdd.ValueMember = "SId";
ddlTypeAdd.DataSource = list;
}
private void FormSnacks_Load(object sender, EventArgs e)
{
loadSearchTypeList();
loadAddTypeList();
loadList();
}
private void DgvList_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
DataGridViewRow rows = dgvList.SelectedRows[0];
txtId.Text = rows.Cells["SId"].Value.ToString();
txtTitleSave.Text = rows.Cells["STitle"].Value.ToString();
txtPrice.Text = rows.Cells["SPrice"].Value.ToString();
txtId.Text = rows.Cells["SId"].Value.ToString();
ddlTypeAdd.Text = rows.Cells["STypeId"].Value.ToString();
btnSave.Text = "修改";
}
private void BtnSave_Click(object sender, EventArgs e)
{
string str = txtId.Text.Trim();
Snacks s = new Snacks();
s.SId = txtId.Text;
s.STitle = txtTitleSave.Text;
s.SPrice = txtPrice.Text;
s.STypeId = ddlTypeAdd.SelectedValue.ToString();
s.STypeTitle = ddlTypeAdd.Text;
if (str.Equals("添加時無編號"))
{
if (bll.add(s))
{
MessageBox.Show("添加成功!");
loadList();
}
else
{
MessageBox.Show("添加失敗!");
}
}
else
{
if (bll.update(s))
{
MessageBox.Show("修改成功!");
loadList();
}
else
{
MessageBox.Show("修改失敗!");
}
}
}
private void BtnCancel_Click(object sender, EventArgs e)
{
txtId.Text = "添加時無編號";
txtTitleSave.Text = "";
txtPrice.Text = "";
ddlTypeAdd.SelectedIndex = 0;
btnSave.Text = "添加";
}
private void BtnRemove_Click(object sender, EventArgs e)
{
DataGridViewRow rows = dgvList.SelectedRows[0];
string sid = rows.Cells["SId"].Value.ToString();
if (bll.delete(sid))
{
MessageBox.Show("刪除成功!");
loadList();
}
else
{
MessageBox.Show("刪除失敗!");
}
}
private void TxtTitleSearch_TextChanged(object sender, EventArgs e)
{
loadList();
}
private void DdlTypeSearch_SelectedIndexChanged(object sender, EventArgs e)
{
loadList();
}
private void BtnSearchAll_Click(object sender, EventArgs e)
{
txtTitleSearch.Clear();
ddlTypeSearch.Text = "全部";
}
private void BtnAddType_Click(object sender, EventArgs e)
{
FormSnacksType fst = new FormSnacksType();
fst.StartPosition = FormStartPosition.CenterScreen;
if (fst.ShowDialog() == DialogResult.Yes)
{
loadAddTypeList();
loadSearchTypeList();
}
}
}
}
點擊首頁的“分類管理“按鈕會打開零食分類頁面(這裏我給這個按鈕起名叫btnAddType,,命名不嚴謹了),其實零食分類管理和零食管理的原理都一樣都是增刪查改。
零食分類界面:
事件代碼:
using BLL;
using MODEL;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace UI
{
public partial class FormSnacksType : Form
{
public FormSnacksType()
{
InitializeComponent();
}
SnacksTypeBLL bll = new SnacksTypeBLL();
private DialogResult dr = DialogResult.No;
//刷新
private void loadList()
{
List<SnacksType> list = bll.getList();
dgvList.AutoGenerateColumns = false;
dgvList.DataSource = list;
}
private void FormSnacksType_Load(object sender, EventArgs e)
{
loadList();
}
private void BtnSave_Click(object sender, EventArgs e)
{
string str = txtId.Text.Trim();
if (str.Equals("添加時無編號"))
{
SnacksType s = new SnacksType();
s.STitle = txtTitle.Text;
if (bll.add(s))
{
MessageBox.Show("添加成功!");
loadList();
dr = DialogResult.Yes;
}
else
{
MessageBox.Show("添加失敗!");
}
}
else
{
SnacksType s = new SnacksType();
s.SId = txtId.Text;
s.STitle = txtTitle.Text;
if (bll.update(s))
{
MessageBox.Show("修改成功!");
loadList();
dr = DialogResult.Yes;
}
else
{
MessageBox.Show("修改失敗!");
}
}
}
private void DgvList_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
DataGridViewRow rows = dgvList.SelectedRows[0];
txtId.Text = rows.Cells["SId"].Value.ToString();
txtTitle.Text = rows.Cells["STitle"].Value.ToString();
btnSave.Text = "修改";
}
private void BtnCancel_Click(object sender, EventArgs e)
{
txtId.Text = "添加時無編號";
txtTitle.Text = "";
btnSave.Text = "添加";
}
private void BtnRemove_Click(object sender, EventArgs e)
{
DataGridViewRow row = dgvList.SelectedRows[0];
string sid = row.Cells["SId"].Value.ToString();
if (bll.delete(sid))
{
MessageBox.Show("刪除成功!");
loadList();
dr = DialogResult.Yes;
}
else
{
MessageBox.Show("刪除失敗!");
}
}
private void FormSnacksType_FormClosing(object sender, FormClosingEventArgs e)
{
this.DialogResult = dr;
}
}
}
三、運行結果
運行要注意把Program中的運行窗體改爲我們需要的,比如這裏是FormSnacks();
數據顯示ok:
分類查找模糊查找ok:
添加數據就直接在右側輸入相關信息,點擊添加就ok了;
刪除數據選中數據所在行,點擊刪除按鈕就ok了;
修改是雙擊修改信息所在行,該信息就會被讀取輸出在右側修改欄(此時右側添加按鈕變爲修改按鈕),在輸出的數據上編輯爲修改後數據,點擊修改即可完成:
點擊分類管理,會打開零食分類界面,該頁面的操作原理同零食管理界面: