三层架构实践入门(1)

三层架构最初目的是不把数据库操作语句放到界面里,虽然可以写个公共类操作数据库,但是SQL语句还是免不了。这样做小项目没有什么问题,但是项目做大了就会难以维护。三层架构把数据访问、业务逻辑、界面分离,方便大项目维护。

为了减少难度,这里举个简单的三层架构雏形:只用DAL(Data Access Layer)层,把数据访问封装到DAL层中,UI调用DAL,原则:UI不能出现SQL。

比如我们有个表:


第0列


第一列


第二列


第三列


Id


Name


Age


Hobby


1


泰迪熊


18


勾搭妹子


2


王旭


30


勾搭妹子

图 1  1   数据库T_Student表

我们添加一个类StudentDAL,SqlHelper是我们上次讲过的。

class StudentDAL

{

public static int GetCount()

{

return (int)SqlHelper.ExecuteScalar(“select count(*) from  T_Student”);

}

}

然后在UI层上就可以代入

label1.Text= (StudentDAL.GetCount()).ToString();

但是当列非常多,参数就会非常多,这时候就要把参数封装到Model中。这里我们建一个类Student。

class Student

{

public long Id{get;set;}

public string Name{set;get;}

public int Age{set;get;}

public string Hobby{set;get;}//可空列注意int?问题

}

然后在class StudentDAL类中添加方法

public static void Insert(Student student)

{

SqlHelper.ExecuteNonQuery(@”Insert into T_Student(Name,Age,Hobby)Values(@Name,@Age,@Hobby)”,new SqlParameter(“@Name”,student.Name), new SqlParameter(“@Age”,student.Age), new SqlParameter(“@Hobby”,student.Hobby));

}

UI层就可以直接跟student打交道了。注意:DAL尽量不要返回DataTable和DataRow之类的ADO.NET类。

比如把界面上的数据插入到数据库,这时候先把界面上的数据写入一个Student对象,然后把Student对象作为参数调用StudentDAL类。

总结下基本步骤:

(1)写实体类,实体类对应数据库中的列。比如:

public class Customer

{

public long Id { get; set; }

public string Name { get; set; }

public DateTime? BirthDay { get; set; }

public string Address { get; set; }

public string TelNum { get; set; }

public int CustLevel { get; set; }

}

(2)写DAL类,DAL类要实现把数据库读取到类中、把类实例化的数据放到数据库里的多种方法。比如:

public class CustomerDAL

{

//把DataRow中数据放入实例化的类并返回

private Customer ToCustomer(DataRow row)

{

Customer cust = new Customer();

cust.Id = (long)row["Id"];

cust.Name = (string)row["Name"];

cust.BirthDay =                 (DateTime?)SqlHelper.FromDbValue(row["BirthDay"]);

cust.Address = (string)row["Address"];

cust.CustLevel = (int)row["CustLevel"];

cust.TelNum = (string)row["TelNum"];

return cust;

}

//通过id查找数据库,返回给实例化的实体类。

public Customer GetById(long id)

{

DataTable dt = SqlHelper.ExecuteDataTable("select * from T_Customer where [email protected]",

new SqlParameter("@Id", id));

if (dt.Rows.Count <= 0)

{

return null;

}

else if (dt.Rows.Count > 1)

{

throw new Exception("严重错误,查出多条数据!");

}

else

{

DataRow row = dt.Rows[0];

return ToCustomer(row);

}

}

//根据id删除数据库中的元素

public void DeleteById(long id)

{

SqlHelper.ExecuteNonQuery("delete from T_Customer where [email protected]",

new SqlParameter("@Id", id));

}

//把实体类中的数据插入数据库(新增数据)

public void Insert(Customer customer)

{

SqlHelper.ExecuteNonQuery(@"INSERT INTO [T_Customer]

([Name]

,[BirthDay]

,[Address]

,[TelNum]

,[CustLevel])

VALUES

(@Name, @BirthDay,@Address,@TelNum,@CustLevel)",

new SqlParameter("@Name",customer.Name),

new SqlParameter("@BirthDay", SqlHelper.ToDbValue(customer.BirthDay)),

new SqlParameter("@Address", customer.Address),

new SqlParameter("@TelNum", customer.TelNum),

new SqlParameter("@CustLevel", customer.CustLevel));

}

//把实体类中的数据插入数据库(修改数据)

public void Update(Customer customer)

{

SqlHelper.ExecuteNonQuery(@"UPDATE [T_Customer]

SET [Name] = @Name

,[BirthDay] = @BirthDay

,[Address] = @Address

,[TelNum] = @TelNum

,[CustLevel] = @CustLevel

WHERE [email protected]",

new SqlParameter("@Name",customer.Name),

new SqlParameter("@BirthDay", SqlHelper.ToDbValue(customer.BirthDay)),

new SqlParameter("@Address", customer.Address),

new SqlParameter("@TelNum", customer.TelNum),

new SqlParameter("@CustLevel", customer.CustLevel)

,new SqlParameter("@Id",customer.Id));

}

//获得全部数据并返回实体类的一个数组

public Customer[] GetAll()

{

DataTable table =  SqlHelper.ExecuteDataTable("select * from T_Customer");

Customer[] customers = new Customer[table.Rows.Count];

for (int i = 0; i < table.Rows.Count; i++)

{

DataRow row = table.Rows[i];

customers[i] = ToCustomer(row);

}

return customers;

}

}

接着做个实验举例:

首先设计WPF窗体,命名CustomerList,注意最上面三个图标本质上是button控件,XAML代码如下:

<Button Name="btnEdit" Click="btnEdit_Click">

<Image Source="Images/edit.ico"></Image>

</Button>

下面是DataGrid数据表格控件,用来显示数据,同时绑定实体类的属性,XAML代码如下:

<DataGrid AutoGenerateColumns="False" Name="gridCustomers" IsReadOnly="True" DockPanel.Dock="Top">

<DataGrid.Columns>

<DataGridTextColumn Header="姓名" Width="100" Binding="{Binding Name}"></DataGridTextColumn>

<DataGridTextColumn Header="生日" Width="100" Binding="{Binding BirthDay}"></DataGridTextColumn>

<DataGridTextColumn Header="电话" Width="100" Binding="{Binding TelNum}"></DataGridTextColumn>

<DataGridTextColumn Header="地址" Width="150" Binding="{Binding Address}"></DataGridTextColumn>

<DataGridTextColumn Header="等级" Width="50" Binding="{Binding CustLevel}"></DataGridTextColumn>

</DataGrid.Columns>

</DataGrid>

编辑CustomerEdit窗体

进行数据绑定,XAML代码如下:

<TextBox Text="{Binding Name}" Height="23" HorizontalAlignment="Left" Margin="92,9,0,0" Name="txtName" VerticalAlignment="Top" Width="120" TabIndex="1" />

<TextBox Text="{Binding TelNum}" Height="23" HorizontalAlignment="Left" Margin="368,8,0,0" Name="txtTelNum" VerticalAlignment="Top" Width="120" TabIndex="4" />

<DatePicker SelectedDate="{Binding BirthDay}" Height="25" HorizontalAlignment="Left" Margin="92,53,0,0" Name="dpBirthDay" VerticalAlignment="Top" Width="120" TabIndex="2" />

<TextBox Text="{Binding CustLevel}" Height="23" HorizontalAlignment="Left" Margin="370,50,0,0" Name="txtCustLevel" VerticalAlignment="Top" Width="120" TabIndex="5" />

<TextBox Text="{Binding Address}" Height="23" HorizontalAlignment="Left" Margin="92,106,0,0" Name="txtAddress" VerticalAlignment="Top" Width="474" TabIndex="3" />

在CustomerEdit窗体类中添加如下代码:

//设置表示字段:是新增数据还是修改数据,由CustomerList赋值

public bool IsInsert { get; set; }

//设置标识字段,如果是编辑的话获得被编辑行的Id,,由CustomerList赋值

public long EditingId { get; set; }

public CustomerEdit()

{

InitializeComponent();

}

private void btnSave_Click(object sender, RoutedEventArgs e)

{

//如果是标识字段是新增,则把控件中的数据插入数据库

if (IsInsert)

{

Customer customer = new Customer();

customer.Address = txtAddress.Text;

customer.BirthDay = dpBirthDay.SelectedDate;

customer.CustLevel = Convert.ToInt32(txtCustLevel.Text);

customer.Name = txtName.Text;

customer.TelNum = txtTelNum.Text;

new CustomerDAL().Insert(customer);//插入数据库

//有Bug,没有判断是否是空

}

else

{

//如果不是新增,是编辑,先从数据库中查询旧的值,然后把界面中的值设置到旧对象上,然后Update更新

CustomerDAL dal = new CustomerDAL();

Customer customer = dal.GetById(EditingId);

customer.Address = txtAddress.Text;

customer.BirthDay = dpBirthDay.SelectedDate;

customer.CustLevel = Convert.ToInt32(txtCustLevel.Text);

customer.Name = txtName.Text;

customer.TelNum = txtTelNum.Text;

dal.Update(customer);

}

DialogResult = true;

}

private void btnCancel_Click(object sender, RoutedEventArgs e)

{

DialogResult = false;

}

private void Window_Loaded(object sender, RoutedEventArgs e)

{

//窗口打开的时候让第一个输入控件获得焦点

txtName.Focus();

if (IsInsert)

{//给控件赋初始值

txtName.Text = ““;

txtTelNum.Text = “”;

txtAddress.Text =“”;

txtCustLevel.Text = “”;

dpBirthDay.SelectedDate =“”;

}

else//修改

{

////把要编辑的数据从数据库中取出来

////可以把Customer直接在ListUI传进来,这样还省得查一次数据库

Customer customer = new CustomerDAL().GetById(EditingId);

////但是,一个原则:窗口传值、容器中存储值尽量放简单数据类型

////填充到界面上,显示编辑前的值

txtName.Text = customer.Name;

txtTelNum.Text = customer.TelNum;

txtAddress.Text = customer.Address;

txtCustLevel.Text = customer.CustLevel.ToString();

dpBirthDay.SelectedDate = customer.BirthDay;

}

}

最后是完成CustomerList,代码如下:

//加载时加载数据

private void Window_Loaded(object sender, RoutedEventArgs e)

{

LoadData();

}

private void LoadData()

{//获得所有的数据

CustomerDAL dal = new CustomerDAL();

gridCustomers.ItemsSource = dal.GetAll();

}

private void btnAdd_Click(object sender, RoutedEventArgs e)

{

CustomerEdit editUI = new CustomerEdit();

edit.IsInsert = true;//插入,如果

if (edit.ShowDialog() == true)

//如果显示Edit对话框,刷新所有数据

{

LoadData();

}

}

private void btnEdit_Click(object sender, RoutedEventArgs e)

{//把选择的对象赋给实体类

Customer customer = (Customer)gridCustomers.SelectedItem;

if(customer==null)

{

MessageBox.Show("请选择要编辑的行!");

return;

}

CustomerEdit editUI = new CustomerEdit();

editUI.IsInsert = false;

editUI.EditingId = customer.Id;

if (editUI.ShowDialog() == true)

{

LoadData();

}

}

//删除

private void btnDelete_Click(object sender, RoutedEventArgs e)

{

Customer customer = (Customer)gridCustomers.SelectedItem;

if (customer == null)

{

MessageBox.Show("请选择要删除的行!");

return;

}

if (MessageBox.Show("确认删除此条数据吗?", "提醒",

MessageBoxButton.YesNo) == MessageBoxResult.Yes)

{

new CustomerDAL().DeleteById(customer.Id);

LoadData();//刷新数据

}

}

时间: 2024-10-08 10:36:26

三层架构实践入门(1)的相关文章

Angular JS从入门基础 mvc三层架构 常用指令

Angular JS从入门基础  mvc模型 常用指令 ★ 最近一直在复习AngularJS,它是一款优秀的前端JS框架,已经被用于Google的多款产品当中.AngularJS有着诸多特性,最为核心的是:MVC.模块化.自动化双向数据绑定.语义化标签.依赖注入等等. 1.常用指令 AngularJS 通过指令扩展了HTML,且通过表达式绑定数据到 HTML.下面我们看一下AngularJS中的常用指令. (1).基本概念 指令:AngularJS中,通过扩展HTML的属性提供功能.所以,ng-

MVC项目实践,在三层架构下实现SportsStore-02,DbSession层、BLL层

SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管理.图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离.本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能. 本篇为系列第二篇,包括: ■ 4.三层架构设计    □ 4.2 创建DbSession层 数据访问层的统一入口   

MVC项目实践,在三层架构下实现SportsStore-01

SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管理.图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离.本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能. 本篇为系列第一篇,包括: ■ 1.搭建项目■ 2.卸载Entity Framework组件,并安装最新版本■ 3.使用

三层架构入门实例

三层架构(3-tier architecture) 通常意义上的三层架构就是将整个业务应用划分为:表现层(UI).业务逻辑层(BLL).数据访问层(DAL).区分层次的目的即为了"高内聚,低耦合"的思想. 首先我们先用一组生活中的图片来说明三层的重要性.(摘自网络) 生活中的实例  饭店有三个分工,服务员,厨师和采购员 分三层,松耦合,更方便应对变化. 实际这种思想也适用于我们的三层架构. UI只负责显示和采集用户操作,不包含任何的业务相关的逻辑处理. BLL 负责处理业务逻辑,通过U

MVC项目实践,在三层架构下实现SportsStore-01,EF Code First建模、DAL层等

http://www.cnblogs.com/darrenji/p/3809219.html 本篇为系列第一篇,包括: ■ 1.搭建项目■ 2.卸载Entity Framework组件,并安装最新版本■ 3.使用EF Code First创建领域模型和EF上下文■ 4.三层架构设计    □ 4.1 创建DAL层        ※ 4.1.1 MySportsStore.IDAL详解        ※ 4.1.2 MySportsStore.DAL详解 1.搭建项目 MySportsStore.

MVC项目实践,在三层架构下实现SportsStore-03,Ninject控制器工厂等

SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管理.图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离.本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能. 本篇为系列第三篇,包括: ■ 5.自定义Ninject控制器工厂■ 6.项目的第一次运行 5.自定义Ninject控制

MVC项目实践,在三层架构下实现SportsStore-08,部署到IIS服务器

SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管理.图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离.本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能. 本篇为系列第八篇,包括: ■ 10.部署到IIS服务器    □ 10.1 使用Visual Studio发布   

MVC项目实践,在三层架构下实现SportsStore-05,实现导航

SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管理.图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离.本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能. 本篇为系列第五篇,包括: ■ 8.导航 8.导航 创建NavController,派生于BaseController:

MVC项目实践,在三层架构下实现SportsStore-04,实现分页

SportsStore是<精通ASP.NET MVC3框架(第三版)>中演示的MVC项目,在该项目中涵盖了MVC的众多方面,包括:使用DI容器.URL优化.导航.分页.购物车.订单.产品管理.图像上传......是不错的MVC实践项目,但该项目不是放在多层框架下开发的,离真实项目还有一段距离.本系列将尝试在多层框架下实现SportsStore项目,并用自己的方式实现一些功能. 本篇为系列第四篇,包括: ■ 7.添加分页 7.添加分页 关于分页,是一系列的a标签,可以通过扩展HtmlHelper