在实际的开发过程中,我们感觉到,数据实体层采用这种设计模式具有以下优点:· 实体类定义XML文件可以通过工具来自动生成,减轻开发工作量。· 在执行查询操作时,不论是返回一个实体,还是多个实体,数据的表现方式都一样,都是EntityData,而不存在如上面所述的单个对象和数据集的表现方式不统一的问题。· 在修改实体类的定义时,如果修改的部分不涉及到业务逻辑的处理,只需要修改XML文件就可以了,不用修改其它程序和重新编译。· 系统提供的实体对象缓存服务可以大大提高了系统的性能。· 类构造工厂的设计模式大大提高了系统的灵活性。 实体控制层解决和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;
}
}  
业务外观层业务外观层为 Web 层提供处理、浏览和操作的界面。业务外观层用作隔离层,它将用户界面与各种业务功能的实现隔离开来。业务外观层只是将已经完成的系统功能,根据各个模块的需要,对业务规则进行高层次的封装。框架没有规定采用在业务外观层采用何种实现方式,但是建议使用Web Service来提供服务。采用IIS为Web服务器,可以很方便的部署Web Service。· Web层Web 层为客户端提供对应用程序的访问。Web 层由 ASP.NET Web 窗体和代码隐藏文件组成。Web 窗体只是用 HTML 提供用户操作,而代码隐藏文件实现各种控件的事件处理。通常,对于数据维护类型的ASP.NET Web 窗体和控件事件处理代码,我们提供了工具来生成,减轻开发工作量。除了上述6个逻辑层以外,系统通常还包括一个系统配置项目,提供应用程序配置和跟踪类。框架服务的设计策略为了能够很好的支持上面所述的系统架构,我们需要一套核心的类库,以实现对构筑其上的应用软件的支持。这样,在具体每个应用系统的开发时,可以省略很多基础性的工作,提高开发的效率。在这个方面,我们设计了以下核心类和接口:· EntityData:定义实体类的通用结构· IClassBuilder:定义实体类结构构造的结构。我们预定义了根据这个接口实现的几个标准类:AbstractClassBuilder、SingletableClassBuilder、ThickClassBuilder、StandardClassBuilder。这些Builder通过ClassBuilderFactory进行管理。· IEntityDAO:定义实体控制类的接口· EntityDataManager:提供对所有实体类的缓存管理和查找服务· DBCommon:封装数据库操作· ApplicationConfiguration:记录系统配置· SqlManager:管理系统的SQL语句及其参数。通过这些核心的类和接口,框架能够为应用系统提供如下服务:· O-R Map:对象-关系数据库映射服务

解决方案 »

  1.   

    已经被收录到新的程序员精华本中了,相关链接:
    http://industry.ccidnet.com/pub/disp/Article?columnID=340&articleID=28940&pageNO=1
      

  2.   

    我不是孙亚民,我正在做这方面的设计。希望和大家共同进步。下载请去Google搜索。
      

  3.   

    http://developer.ccidnet.com/pub/html/developer/depstar/templates/0210.htm看
      

  4.   

    我也看了,不过对我来说有点难度,是一个"模式"的问题吧,
    关于他们说的那个可以自动生成代码的工具我倒是很有兴趣,因为很多时候代码都是类似的重复.....
    前段时间有个.net方法生成器,还有n tier generator都是这类的工具吧....如果是数据库前端的开发我想这些工具非常有用,不过是你自己可以理解的那种最好,因为你也有自己的"模式".....
    一点个人看法.