博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

ADO.NET入门(3)---三层设计

Posted on 2006-09-20 18:51  tshark  阅读(2764)  评论(6)    收藏  举报

ADO.NET不仅是上面两篇中讲的那么多,第2篇中的数据库通用访问类也是对本篇的一个基础铺垫,通用访问类是一层,用户界面是一层,用户直接和数据库通用访问类打交道,但是在实际设计中并不这么写,一般使用三层甚至多层(大多为三层)。本文主要探讨一下ADO.NET中的三层设计,由于经验有限,所以内容比较浅,只是带领大家了解一下三层的基本设计。

数据库通用访问类的出现让我们不必直接和数据库打交道,从而让数据库和用户分离,保护了数据库,所有的操作都是  用户<--->通用访问类<--->数据库  这种操作,这是两层的设计,三层设计对两层有了一个新的扩展,用户<--->实体类<--->数据库通用访问类<---->数据库。

实体类是增加的一个类,但是在实际项目工程中一般使用的是 数据访问层--业务层--界面,其实意思差不多,我在这里也不是讨论实际项目工程和我所阐述的理论三层的区别和联系,只要大家了解了基本意思,对层的分离与结合有一个理性认识,就能在开发中领会三层架构了。


--------------------------------------------------

举例说明(虽然不是真正的项目,但是也有点代表性)

数据库中有一张表:

员工编号 员工姓名 员工工资
1    张三  2000
2  李四  2500
3  王五  3000

在查询分析器中执行如下代码:
use Northwind
go

create table emp(emp_id int,emp_name varchar(20),emp_salary money)
go

insert emp values('1','张三',2000)
insert emp values('2','李四',2500)
insert emp values('3','王五',3000)
go
表就建立起来

我们要对这个表进行一些操作,和第2篇不同的就是,三层的设计只是多了一个实体类而已,具体方法只是稍微改变一下。

步骤1:
通用数据库访问类的设计(暂时没涉及到数据库的切换)。通用数据库访问类相当于实际工作中的数据访问层,所有涉及到数据库的操作都写在这个类里面。在实际工作中,项目团队中可能有专门人员来做这个访问类,比如说A,所有涉及到数据库的操作都由A来负责,其他人员可以专心做自己的设计比如说B和C,B只要把自己部分的要求告诉A,B需要一个有返回值的方法,返回类型为数据集,但是传的是不确定个数的参数,希望A能解决。A就给B做了一个带参数集的方法,告诉B这个方法需要两个参数,一个存储过程,一个参数数组,B也明白了调用方法,这样B就可以不管如何对数据库访问了,然后做好了自己的某个公用类。同样C也有问题,在调用B做好的那个非常好用的公用类时,发现在某些情况下需要修改这个B做的公用类,因为B的这个公用类里面差一些和数据库相关的方法,这些方法B不用但是C需要。在项目中C是不能修改B做的类的,但是他又想用,所以只能和A联系,让A再做一些方法和数据库访问,从而能让自己使用。
比较饶口,意思就是,业务逻辑层和数据逻辑层一定要分开做,三层架构里面最好不要出现业务与数据混杂的情况。

数据库通用访问类的设计在上篇中讲到过,在这里只有四个基本方法

using System;
using System.Data;
using System.Data.SqlClient;

namespace 三层test
{
 
public class DBAccess
 
{
  
private SqlConnection conn;

  
public DBAccess()
  
{
   conn 
= new SqlConnection("server=.;uid=sa;pwd=sa;database=Northwind");
  }

  
public void Open()
  
{
   conn.Open();
  }

  
public void Close()
  
{
   conn.Close();
  }


  
public void ExecuteWithoutReturn(string proc)
  
{
   SqlCommand cmd 
= new SqlCommand(proc,conn);
   cmd.CommandType 
= CommandType.StoredProcedure;
   cmd.ExecuteNonQuery();
  }

  
public void ExecuteWithoutReturn(string proc,SqlParameter[] paraList)
  
{
   SqlCommand cmd 
= new SqlCommand(proc,conn);
   cmd.CommandType 
= CommandType.StoredProcedure;

   
foreach(SqlParameter elem in paraList)
   
{
    cmd.Parameters.Add(elem);
   }

   cmd.ExecuteNonQuery();
  }

  
public DataSet ExecuteWithReturn(string proc)
  
{
   SqlCommand cmd 
= new SqlCommand(proc,conn);
   cmd.CommandType 
= CommandType.StoredProcedure;

   SqlDataAdapter da 
= new SqlDataAdapter(cmd);
   DataSet ds 
= new DataSet();
   da.Fill(ds);
   
return ds;
  }

  
public DataSet ExecuteWithReturn(string proc,SqlParameter[] paraList)
  
{
   SqlCommand cmd 
= new SqlCommand(proc,conn);
   cmd.CommandType 
= CommandType.StoredProcedure;
   
   
foreach(SqlParameter elem in paraList)
   
{
    cmd.Parameters.Add(elem);
   }

   SqlDataAdapter da 
= new SqlDataAdapter(cmd);
   DataSet ds 
= new DataSet();
   da.Fill(ds);
   
return ds;
  }

 }

}

 

在实际项目中,可能会出现比数据库逻辑层(上面这个层)还要低一级的层,这个层有人说是第四层,一般来说以本项目组名称或者是本公司名称为名,将一些非常常用和有用的全部集合起来,这个层会越来越大,在几乎所有的项目中都会运用到.

上面四个有返回无返回的方法在第2篇中有详细解释.

 

步骤2:
实体类的设计.

添加一个类叫Emp.cs.实体类的要求就是和数据库对应,我们要这个实体类就是对emp表中的数据操作,所以我们不直接去访问数据库,什么操作都交给实体类去完成.
首先做个存储过程,查询语句的存储过程,按照id查找:如图
winform建立

顺便写一个全部显示的存储过程:

CREATE PROCEDURE dbo.ShowAll

AS
 
select * from emp
 
RETURN 


 

如图:


等下窗体加载的时候调用.
实体类第一部分:窗体加载时显示数据库中emp表中内容到窗体上.

public DataSet ShowAll()
  {
   DBAccess dba 
= new DBAccess();---3
   dba.Open();

   DataSet ds 
= dba.ExecuteWithReturn("dbo.ShowAll");---4
   
return ds;---5
  }


窗体加载的代码为:(这个为UI用户层代码)

private void Form1_Load(object sender, System.EventArgs e)
  {
   Emp emp 
= new Emp();---1
   
   
this.dataGrid1.DataSource=emp.ShowAll().Tables[0];---2
  }


解释如下:
1.我们是不能直接访问数据库的,在窗体加载时,我们通过实体类来实现功能,new一个emp
2.然后调用emp.ShowAll()方法,这个方法有返回值ds,将这个ds填到datagrid中
3.实体类中和数据库打交道和原来两层一样,new一个DBAccess
4,5.调用dba.ExecuteWithReturn("dbo.ShowAll"),由于是全部显示,所以上面做的存储过程ShowAll就起作用了,传这个参数进去,得到一整张表的返回值,再返回到用户UI的窗体加载中,从而达到目的.

小结:这个其实是走了一个圈子,以前两层的时候直接访问数据库了,现在非要通过一个中间人,麻烦是麻烦了点,但是我们也可以看出一些好处:1.UI代码减少,已经看不到任何和数据库相关的东西,连存储过程都没写.UI只需要把自己的界面设计好,这样可以更加专业.2.批量代码可以在中间的业务层实现,在以后的移植以及升级过程中,比如winform到web,我们不必修改太多代码,复制粘贴就够了,因为我们不需要和界面打交道.


窗体加载完毕后,我们来查找.用编号来查找(最简单):
实体类第二部分:查找功能

public DataSet Select()
  {
   DBAccess dba 
= new DBAccess();
   dba.Open();

   SqlParameter para 
= new SqlParameter("@emp_id",SqlDbType.Int);---2
   para.Value
=m_id;---3
   SqlParameter[] paraList
={para};---4

   DataSet ds 
= dba.ExecuteWithReturn("select",paraList);

   
return ds;
  }

  
用户界面查找按纽代码:
 

 private void button1_Click(object sender, System.EventArgs e)
  {
   Emp emp 
= new Emp();
   
   emp.M_id
=Convert.ToInt32(this.textBox1.Text);---1

   
this.dataGrid1.DataSource = emp.Select().Tables[0];
  }

解释:
1.比窗体加载多一点,这个是赋值的过程,将要查找的ID赋值给emp的m_id
2.实体类中做参数
3.这个参数的值为m_id,而m_id是等于textbox1的内容的
4.做成参数数组,在未知参数数量时这个方法较好.


实体类第三部分:刷新功能.
直接调用ShowAll()吧.
实体类中写: 

public DataSet Refresh()
  {
   
return ShowAll();
  }

用户窗体中写:

private void button3_Click(object sender, System.EventArgs e)//刷新按钮
  {
   Emp emp 
= new Emp();
   
this.dataGrid1.DataSource = emp.Refresh().Tables[0];
  }

当然也可以重新load一下,那样更省力....

所有步骤演示如图:
step1step1
step2step2
step3step3
step4step4


另:update存储过程的代码:

CREATE PROCEDURE dbo.[Update]

 (
  
@emp_id int,
  
@emp_salary money

 )

AS
 
update emp set emp_salary =@emp_salary where emp_id=@emp_id
 
RETURN 



全部代码已经写完了,希望大家能对三层的设计有些了解.现在还是简单的,而且winform在我们以后的工作中应该没有ASP.NET多.

 


对ASP.NET的三层设计过几天再写.现在正郁闷...