UML软件工程组织

实战揭秘:开发.Net平台应用系统框架(1)
作者:孙亚民 本文选自:赛迪网 2002年10月28日

 

实体控制层

解决和O-R Map的问题,需要考虑的就是实体类的持久性问题了,也就是同数据库的交互问题。实体控制层用于控制数据的基本操作,如增加、修改、删除、查询等,同时为业务规则层提供数据服务。

实体控制层的类实现IEntityDAO接口。这个接口定义了实现数据操纵的主要必要方法,包括增加、修改、删除和查找。IEntityDAO的定义如下:

public interface IEntityDAO : IDisposable
{
void InsertEntity(EntityData entity);
void UpdateEntity(EntityData entity);
void DeleteEntity(EntityData entity);
EntityData FindByPrimaryKey(object strKeyValue);
}


可以看到,这个接口同J2EE中EntityBean的接口定义很象,实际上,我们也是参考了EntityBean的解决方案。

下面是一个Product的DAO类的例子:

public class ProductEntityDAO: IEntityDAO
{
private DBCommon db; //这是数据库访问的类
public ProductEntityDAO()
{
db=new DBCommon();
db.Open();
}
public ProductEntityDAO(DBCommon cdb)
{
this.db=cdb;
}
// 插入一个实体
public void InsertEntity(EntityData entity)
{
CheckData(entity);
db.BeginTrans();
try
{
foreach(DataRow row in
entity.Tables["Product"].Rows)
db.exeSql(row,SqlManager.GetSqlStruct("Product","InsertProduct"));
db.CommitTrans();
}
catch(Exception e)
{
db.RollbackTrans();
throw e;
}
}

//修改一个实体类
public void UpdateEntity(EntityData entity)
{
CheckData(entity);
db.BeginTrans();
try
{
foreach(DataRow row in
entity.Tables["Product"].Rows)
if(row.RowState!=DataRowState.Unchanged)
db.exeSql(row,SqlManager.GetSqlStruct("Product","UpdateProduct"));
db.CommitTrans();
}
catch(Exception e)
{
db.RollbackTrans();
throw e;
}
}
//删除一个实体类
public void DeleteEntity(EntityData entity)
{
CheckData(entity);
db.BeginTrans();
try
{
foreach(DataRow row in
entity.Tables["Product"].Rows)
db.exeSql(row,SqlManager.GetSqlStruct("Product","DeleteProduct"));
db.CommitTrans();
}
catch(Exception e)
{
db.RollbackTrans();
throw e;
}
}
//查找实体类
public EntityData FindByPrimaryKey(object KeyValue)
{
EntityData entity=new EntityData("Product");
SqlStruct
sqlProduct=SqlManager.GetSqlStruct("Product","SelectByIDProduct");
db.FillEntity(sqlProduct.SqlString,sqlProduct.ParamsList[0],
KeyValue,entity,"Product");
return entity;
}
public EntityData FindAllProduct()
{
EntityData entity=new EntityData("Product");
SqlStruct
sqlProduct=SqlManager.GetSqlStruct("Product","FindAllProduct");
db.FillEntity(sqlProduct.SqlString,null,null,entity,"Product");
return entity;
}
// 校验数据数据输入的有效性
private void CheckData(EntityData entity)
{
if(entity.Tables["Product"].Rows[0]["ProductID"].ToString().Length>40)
throw new ErrorClassPropertyException
("Property ProductID should be less than 40 characters");
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(true);
}
protected virtual void Dispose(bool disposing)
{
if (! disposing)
return; // we're being collected,
so let theGC take care of this object
db.Close();
}
}


同数据实体层相结合,这两部分实现了应用服务层同数据库的交互。这两个部分结合,完成了类似于J2EE中EntityBean的功能。

采用数据实体和实体控制分开的设计方法,具有以下优点:

· 避免了J2EE体系中操纵EntityBean系统资源消耗大,效率低下的缺陷。

· 解决了J2EE体系中使用EntityBean传输数据时开销大,过程复杂、效率低的缺陷。

· 可以单独修改实体结构和对实体数据的操纵,使得系统更加灵活

· 数据实体的XML定义文件和实体控制层的类可以通过工具自动生成,减轻开发工作量。

数据访问层

为了为实体控制层提供对数据库操作的服务,我们设计了这个部分。这个层次通常执行以下一些操作:

· 连接数据库

· 执行数据库操作

· 查询数据库,返回结果

· 维护数据库连接缓存

· 数据库事务调用

为了统一对数据的访问方式,我们在设计的时候,在框架的类库中包含了数据访问服务,封装了常用的对各种数据库的操作,可以访问不同类型的数据库,这样,在具体软件系统开发的时候,可以不用考虑同数据库的连接等问题,也使得应用系统在更换数据库时,不用修改原有的代码,大大简化了开发和部署工作。数据访问服务还维护数据库连接缓存,提高系统性能,以及对数据库事务调用的服务。

数据访问服务在核心类库中主要通过DBCommon类来提供对数据访问功能调用的服务。DBCommon的使用方法在上面的ProductEntityDAO中可以看出一二。更多的可以看看Demo工程中的使用。

业务规则层

业务规则层需要完成的功能是各种业务规则和逻辑的实现。业务规则完成如客户帐户和书籍订单的验证这样的任务。这是整个应用系统中最为复杂的部分,没有太多的规律可循。但是,我们在完成上面的工作后,对于这个部分的开发,也可以起到一定的简化的工作。这从下面的例子可以看到。

业务规则层的设计通常需要进行很好的建模工作。业务规则的建模,一般采用UML来进行。可以使用UML的序列图、状态图、活动图等来为业务规则建模。这个部分的工作,通常通过一系列的类之间的交互来完成。

业务规则通常要求系统能够支持事务处理(Transaction)。在这个地方,.Net提供了很方便的调用Windows Transaction Server的手段。关于这个部分的内容,各位自己阅读MSDN就非常清楚了,这里就不做详细的介绍了。

例如,在一个库存系统的入库单入库操作中,除了需要保存入库单外,在这个之前,还必须对入库单涉及的产品的数量进行修改,其代码通常如下(使用了事务处理):

public void StoreIntoWarehouse(EntityData IndepotForm)
{
DataTable tbl=IndepotForm.Tables["InDepotFormDetail"];
try
{
ProductEntityDAO ped=new ProductEntityDAO();
for(int i=0;i<tbl.Rows.Count;i++)
{
DataRow formdetail=tbl.Rows[i];
string productID=formdetail["ProductID"].ToString();
decimal
inCount=(decimal)formdetail["InCount"];
EntityData product=ped.FindByPrimaryKey(productID);
DataRow productRow=product.GetRecord("Product");
productRow["CurrentCount"]=(decimal)productRow["CurrentCount"]+inCount;
ped.UpdateEntity(product);
}
ped.Dispose();
InDepotFormEntityDAO inDepotForm=new
InDepotFormEntityDAO();
inDepotForm.InsertEntity(IndepotForm);
IndepotForm.Dispose();
ContextUtil.SetComplete();
}
catch(Exception ee)
{
ContextUtil.SetAbort();
throw ee;
}
}



版权所有:UML软件工程组织