假设有这么一个需求:从连接某个数据库并从中查询某个表的信息,放到程序的位置进行存储。
想必一开始的写法会是下面这样:
#region 根据数据库添加内容
public void FillGridView(DataGridView MyGrid, string Upname, int Count)
{
//新建命令
SqlCommand com = new SqlCommand();
com.Connection = MyConnection;
com.CommandType = CommandType.Text;
//sql语句
com.CommandText = "select * from TAB_ACCESS where ACCESS_LEVEL=1 AND ACCESS_NAME='" + Upname + "'";
//执行语句
SqlDataReader reader = com.ExecuteReader();
string name = null;
string score = null;
//读取数据
while (reader.Read())
{
name = reader["ACCESS_NAME"].ToString();
score = reader["ACCESS_SCORE"].ToString();
}
reader.Close();
//处理读到的数据(实际业务)
int Sum = 0;
for (int j = 0; j < Count; j++)
{
Sum += RootCount[j];
if (RootCount[j] == 0)
Sum++;
}
if (RootCount[Count] > 0)
{
for (int i = 0; i < RootCount[Count]; i++)
{
MyGrid.Rows[Sum + i].Cells[0].Value = name;
MyGrid.Rows[Sum + i].Cells[1].Value = score;
}
}
else
{
MyGrid.Rows[Sum].Cells[0].Value = name;
MyGrid.Rows[Sum].Cells[1].Value = score;
}
}
#endregion
在这一个方法中,能完成业务的所有需求:连接数据库,读数据,处理数据。 程序能良好运行,没有什么问题。
这时,若需要扩展新的业务,或是在后期的运维中需要修改,那么问题就出现了:方法中各自的逻辑都紧紧纠缠在一起,彼此间相互依赖,谁都是不可替换的。只能写新的方法,也就是重新完成连接数据库,读数据,处理数据的操作。这无疑加大了开发和维护的成本,效率很低。
本着 “高内聚,低耦合” 的思想,我们要想办法降低各个业务的耦合性,连接数据库归连接数据库,读数据归读数据,处理数据归处理数据,大家进水不犯河水。于是,在项目中,我们可以考虑采用分层式架构。
最常见的分层架构为(参考百度百科描述):
位于最上层。用于显示数据和接收用户输入的数据,为用户提供一种交互式操作的界面。
业务逻辑层是系统架构中体现核心价值的部分。它的关注点主要集中在业务规则的制定、业务流程的实现等与业务需求有关的系统设计。
业务逻辑层在体系架构中的位置很关键,它处于数据访问层与表示层中间,起到了数据交换中承上启下的作用。由于层是一种弱耦合结构,层与层之间的依赖是向下的,底层对于上层而言是“无知”的,改变上层的设计对于其调用的底层而言没有任何影响。如果在分层设计时,遵循了面向接口设计的思想,那么这种向下的依赖也应该是一种弱依赖关系。因而在不改变接口定义的前提下,理想的分层式架构,应该是一个支持可抽取、可替换的“抽屉”式架构。正因为如此,业务逻辑层的设计对于一个支持可扩展的架构尤为关键,因为它扮演了两个不同的角色。对于数据访问层而言,它是调用者;对于表示层而言,它却是被调用者。依赖与被依赖的关系都纠结在业务逻辑层上,如何实现依赖关系的解耦,则是除了实现业务逻辑之外留给设计师的任务。
数据访问层:有时候也称为是持久层,其功能主要是负责数据库的访问,可以访问数据库、二进制文件、文本文档或是XML文档。简单的说法就是实现对数据表的Select,Insert,Update,Delete的操作。
1、开发人员可以只关注整个结构中的其中某一层;
2、可以很容易的用新的实现来替换原有层次的实现;
3、可以降低层与层之间的依赖;
4、有利于标准化;
5、利于各层逻辑的复用。
6、结构更加的明确
7、在后期维护的时候,极大地降低了维护成本和维护时间
1、降低了系统的性能。这是不言而喻的。如果不采用分层式结构,很多业务可以直接造访数据库,以此获取相应的数据,如今却必须通过中间层来完成。
2、有时会导致级联的修改。这种修改尤其体现在自上而下的方向。如果在表示层中需要增加一个功能,为保证其设计符合分层式结构,可能需要在相应的业务逻辑层和数据访问层中都增加相应的代码。
3、增加了开发成本。
拿最近做的数据库项目的架构来讲,初步的分层架构如下:
在实际应用中的表现是这样的:
Interface 为接口层。在此定义数据库访问接口。
DataModel 为数据模型层。在此定义各种类和结构体用于存储数据(在架构中可以去掉)。
DAL为数据访问层。数据库的连接以及所有对数据库的增删改查都在此实现。
BLL为业务逻辑层。读到的数据在这里进行处理,比如将存储到某个结构体或类中。
假设数据库中存在一个部门表(TAB_DEPART) , 我们需要从中查询所有记录,存到预先定义好的List
操作流程如下图:
Interface定义:
namespace BSH_DBA.Interface
{
///
/// UserDAL接口
///
public interface IUserDAL
{
///
/// 查询所有部门记录
///
/// 连接字段
/// DataTable:成功;其他:失败
DataTable SelectDepartment(string conn);
}
}
DAL中继承接口并写详细数据库操作:
namespace BSH_DBA.DAL
{
///
/// 用户管理模块库数据操作
///
public class UserDAL : IUserDAL
{
///
/// 查询所有部门记录
///
/// 连接字段
/// DataTable:成功;其他:失败
public DataTable SelectDepartment(string conn)
{
StringBuilder MysqlCommand = new StringBuilder();
try
{
MysqlCommand.Append(string.Format(@"select * from {0}", NamedConfig.TAB_DEPART));
DataTable dt = MySqlHelper.ExecuteDataset(conn, CommandType.Text, MysqlCommand.ToString()).Tables[0];
return dt;
}
catch (Exception ex)
{
Trace.TraceError(ex.ToString());
return null;
}
}
}
BAL中调用接口读到数据并存储:
namespace BSH_DBA.BLL
{
///
/// 用户业务
/// 注:用户包括服务人员、管理员、超级管理员、Admin
///
public class UserBLL
{
private static readonly IUserDAL iUser = new UserDAL();
///
/// 查询所有部门记录
///
/// 连接字段
/// 输出:部门列表
/// 0:成功;其他:失败
public static int SelectDepartment(string conn, List list_record)
{
//调用接口,读取数据
DataTable dt = iUser.SelectDepartment(conn);
if(dt == null)
{
return 1;
}
//遍历DataTable,将里面数据存到List中
foreach(DataRow dr in dt.Rows)
{
string id = dr["depart_id"].ToString();
string name = dr["depart_name"].ToString();
string upid = dr["depart_upid"].ToString();
DepartmentRecord drecord = new DepartmentRecord(id,name,upid);
list_record.Add(drecord);
}
return 0;
}
}
}
以上便是以分层架构完成的数据库业务操作。供参考。