一步步构建多层架构系列我将以我原来开发过的海关项目系统为例,但仅抽像出系统架构部分,大致图形如下:
说明:我会一步步完善上面的框架,其中会用到设计模式,webservice构建同步,缓存等
开发.net项目时,我们一般采用三层结构,微软推荐的分层式结构一般分为三层,从下至上分别为:数据访问层、业务逻辑层、表示层。
数据访问层(dal):主要用来访问数据库的增删改查的操作,只不过将对数据库的增删改查封装了而已。这里我们使用微软已封装好的sqlhelp类作为底层数据库操作类,也就是指运用了sqlconnection,sqlcommand,sqlapdater等几个类的操作。
业务逻辑层(bll):主要用于调用数据访问层dal,其中需要传递对象到数据访问层,这个层主要封装了一些业务逻辑,方便界面层来调用。
表示层:是系统的UI部分,负责使用者与整个系统的交互。在这一层中,理想的状态是不应包括系统的业务逻辑。表示层中的逻辑代码,仅与界面元素有关。
具体搭建方法如下:
1.根据客户需求,客户需要同时支持mysql和sqlserver,所以首先我们需要添加底库sqlhelper和mysqlhelper,建立如下图所示的类库,并添加sqlhelper.cs和mysqlhelper.cs,如下图所示:,其中sqlhelper.cs和mysqlhelper类在此处下载/Files/mfm11111/Pyllot.EC.DBUlitily.rar
2.建立DAL数据访问层,因为要同时支持mysql和sqlserver,所以我们需要建立Pyllot.EC.MySqlDal与Pyllot.EC.SqlServerDal类库。以默认数据库pubs库中的Category为例,于是我们构建如下所示的代码,也就是一般的增删改查:
using System;
using System.Collections.Generic;
using System.Text;
using Pyllot.EC.Cargo.IDAL;
using System.Data;
using Pyllot.EC.DBUtility;
using Pyllot.EC.Common;
using Pyllot.EC.Cargo.Model;
using MySql.Data.MySqlClient;
namespace Pyllot.EC.Cargo.MySqlDAL
{
public class Category:ICategory
{
public DataSet GetAll()
{
return Pyllot.EC.DBUtility.MySqlHelper.ExecuteDataset(ConnectionProvider.connStringMySql, CommandType.Text, "select * from op_job");
}
// 选择按照条件
public DataTable SelectByCondition(string strCondition)
{
try
{
DataSet ds = Pyllot.EC.DBUtility.MySqlHelper.ExecuteDataset(ConnectionProvider.connStringMySql, CommandType.Text, "select * from Categories where CategoryName='" + strCondition+"'");
ds.Tables[0].TableName = "bbooks";
return ds.Tables[0];
}
catch (Exception exc)
{
throw exc;
}
}
//测试数据
public CategoriesData GetCategory(string categoryId)
{
CategoriesData category = null;
return category;
}
// 插入数据Insert 返回bool
public bool Insert(CategoriesData data)
{
try
{
Populate Parameters
Pyllot.EC.DBUtility.MySqlHelper.ExecuteNonQuery(ConnectionProvider.connStringMySql, CommandType.Text, "insert into Categories values(?CategoryID,?CategoryName,?Description)", arParams);
return true;
}
catch (Exception exc)
{
throw exc;
}
}
//更新数据,返回bool
public bool Update(CategoriesData data)
{
try
{
Populate Parameters
Pyllot.EC.DBUtility.MySqlHelper.ExecuteNonQuery(ConnectionProvider.connStringMySql, CommandType.Text, "update Categories set CategoryName=?CategoryName,Description=?Description where CategoryID=?CategoryID", arParams);
return true;
}
catch (Exception exc)
{
throw exc;
}
}
public bool Delete(int CategoryID)
{
try
{
Populate Parameters
Pyllot.EC.DBUtility.MySqlHelper.ExecuteNonQuery(ConnectionProvider.connStringMySql, CommandType.Text, "delete from Categories where CategoryID=?CategoryID", arParams);
return true;
}
catch (Exception exc)
{
throw exc;
}
}
}
}
那么,为什么我们要实现接口ICategory呢?原因有三:
其一,这些业务逻辑即为基本的数据库操作,包括Select,Insert,Update和Delete。由于这些业务逻辑对象,仅具有行为而与数据无关,因此它们均被抽象为一个单独的接口模块IDAL,例如数据表Category对应的接口ICategory;
其次,它体现了“抽象”的精神,或者说是“面向接口编程”的最佳体现。抽象的接口模块IDAL,与具体的数据库访问实现完全隔离。这种与实现无关的设计,保证了系统的可扩展性,同时也保证了数据库的可移植性。可以支持SQL Server和mysql,那么它们具体的实现就分别放在两个不同的模块SQLServerDAL、mysqlDAL中。
其三,具体一点讲,在SQLServerDAL、mysqlDAL中都具有类Category,如果业务逻辑层要调用dal时,到底调用哪个类库中的Category呢?如果我们将类的共性抽象出来形成接口时,那么外界仅需要与接口打交道即可。
3.建立类库Pyllot.EC.IDAL,当然从步骤二的原理,我们完全可以想像出此类库下面的类只是规范了每个类的基本行为,例如Category,我们可以得出代码如下:
using System.Collections.Generic;
using System.Text;
using Pyllot.EC.Cargo.Model;
using System.Data;
namespace Pyllot.EC.Cargo.IDAL
{
public interface ICategory
{
DataSet GetAll();
DataTable SelectByCondition(string strCondition);
CategoriesData GetCategory(string categoryId);
bool Insert(CategoriesData data);
bool Update(CategoriesData data);
bool Delete(int CategoryID);
}
}
4.考虑到业务逻辑层与数据访问层的数据对象传递问题,所以我们有必要建一个类库Pyllot.EC.Model,用来放一些数据实体,对应数据库中相应的数据表。它们没有行为,仅用于表现对象的数据。这些实体类都被放到Model程序集中,例如数据表Category对应的实体类CategorieData,其代码格式如下:
using System.Collections.Generic;
using System.Text;
namespace Pyllot.EC.Cargo.Model
{
public class CategoriesData
{
Private Fields
Constructor
Public Properties
}
}
5.现在我们已经有了数据实体,数据对象的抽象接口和实现,可以说有关数据库访问的主体就已经完成了。留待我们的还有两个问题需要解决:
1、数据对象创建的管理。
2、利于数据库的移植。
项目紧,下次见。