最新
推荐
2014年高等教育信息化十大“关... 01-04 教育部成立教育信息化专家组 12-24
CERNET第二十一届学术年会 11-24 李志民:互联网促进人类文明迈... 11-15
|
◆ 一致的数据表示方式。在一个系统中,数据的表示方式必须尽可能统一,同时,在处理单个数据和多个数据的时候,处理方式尽可能一致。
◆ 因为数据通常是需要存储到数据库中,因此,良好的映射方法是必需的。
◆ 处理好对象的粒度,即所谓的粗粒度对象、细粒度对象。
一般例子
考虑一个现实的例子,一个仓库中的产品(Product),在系统中可以使用如下定义:
public class Product{public string Name; //名称 public decimal Price;//价格 public int Count;//数量 } 可以按照如下方法使用Product类: Product p=new Product(); //……处理Product
这是一个包含了三个属性的Product类的定义。为了便于说明,在这里,我们尽量将问题简化了。
又例如,一张入库单可以使用如下定义:
public class Form{public string ID; //入库单编号 public DateTime AddTime; //入库时间 public FormDetail[] FormDetails; //入库单明细 } public class FormDetail { public Product InProduct; //入库产品 public int Count; //入库数量 }
对于处理单个对象,通常采用上述的方法,但是,当我们需要处理相同类的一组对象,也就是处理一个对象集合的时候,就会有一些小小的麻烦。
如前所述,我们希望在处理单个对象和对象集合的时候,处理的方式尽量统一,这对于软件开发的意义是很大的。常用的处理对象集合的方法有:
◆数组表示的方法
例如,上面的例子中当一张入库单包含多条入库单明细的时候采用的方法。为了灵活性,也可以使用容器来,如Java中的Vector或C#的ArrayList(C#)。只是,在处理对象的时候,需要一个类型转换的操作。这个问题,在支持泛型的语言中不会存在,如使用C++的标准库的容器类。
◆ObjectCollection方法。这个方法同上面的方法类似,不同之处在于,为每个实体类设计一个Collection类。例如,可以为FormDetail设计一个FormDetailsCollection类(C#):
public class FormDetailsCollection: ArrayList { public void Add(FormDetail detail) { base.Add(detail); } public new FormDetail this[int nIndex] { get{ return (FormDetail)base[nIndex]; } } }
这么做的好处在于,在操作集合中的对象时,不必进行类型转换的操作。
◆数据集的表示方法。
采用这种方法,通常是直接把从数据库查询中获取的数据集(Recordset)作为数据处理对象。这种方法在ASP应用程序中是非常常见的做法。这种做法简单,初学者很容易掌握,但是弊病也很多。
EJB的方法
在J2EE体系中,对实体对象的处理的典型方法是Entity Bean。J2EE中使用Entity Bean来表示数据,以及封装数据的持久化储存(同数据库的交互)。由于Entity Bean比较消耗资源,而且采用的是远程调用的方式来访问,因此,在需要传递大量数据,或者在不同的层次之间传递数据的时候,往往还会采用一些诸如"值对象"(Value Object)的设计模式来提升性能。关于J2EE中的设计模式的更多内容,读者可以参考《J2EE核心模式》一书。
JDO的方法
相对于J2EE这个昂贵的方法来说,JDO提供了一个相对"轻量级"的方案。在JDO中,你可以采用一般的做法,编写实体类,然后,通过一些强化器对这些类进行强化,以使其符合JDO的规范,最后,你可以通过PersistenceManager来实现对象的持久化储存。
无论是EJB还是JDO,在同数据库进行映射的时候,都选用了XML配置文件的方式。这是一种灵活的方式。由于XML强大的表达能力,我们可以很好的用它来描述代码中的实体类和数据库之间的映射关系,并且,不用在代码中进行硬编码,这样,在情况发生变化的时候,有可能只需要修改配置文件,而不用去修改程序的源代码。关于EJB和JDO的配置文件的更多的信息,各位可以参考相关的文档,这里不再赘述了。
然而,使用XML配置文件的方式并不是唯一的方法,在微软提供的一些案例中,如Duwamish示例,就没有采用这种方式。至于开发人员在开发过程中具体采用哪种方式,是需要根据具体情况进行权衡和取舍的。
Websharp的方法
Websharp在数据的表现上,充分利用了.Net Framework类库中DataSet的功能,设计了一个EntityData类。这个类继承了DataSet,并增加了一些属性和方法。同样的,同数据库的映射关系,也是采用XML配置文件的方式。
在实际的应用中,要获取一个实体对象,可以通过如下方式取得:
EntityData Customer=EntityDataManager. GetEmptyEntity("Customer");
然后,可以通过如下方式来访问这个对象的属性:
string CustomerID=Customer["CustomerID"]
可以看到,这种方式同传统的方式有点不同。在这种方式下,数据的表现形式只有一个,那就是EntityData。其好处是明显的,不用为每个实体都单独编写一个类,能够大大减少代码的编写量。其缺点也很明显,那就是不能利用编译器类型检测的功能,如果在调用对象的属性的时候,写错了属性的名称,就可能出错,但是,这个问题可以通过工具来解决。 关于这个方面更加详细的信息,可以参见拙文:
《利用.Net框架开发应用系统 》
《 实战揭秘:开发.Net平台应用系统框架》
数据的存取方式
数据存取的目的,是持久化保存对象,以备后来的使用,如查询、修改、统计分析等。存取的对象,可以是数据库、普通文件、XML甚至其他任何方式,只要保证数据能够长久保存,并且,不会受断电、系统重起等因素的影响。在这个部分,最理想的状况,自然是能够支持除了数据库以外的各种类型的存取方式,或者,至少留有接口,能够比较方便的扩充。
因为数据库是最常用,也是最有效的数据存储方法,因此,支持数据库存储是最首先必须支持的。在不同的平台下,有不同的数据库访问的手段。例如,在Java平台下,有JDBC,在Windows平台下,可以使用ADO、ADO.Net等。但是,这些手段还比较接近底层,在实际操纵数据库的时候,需要编写大量的代码,并且,我们还需要通过手工的方式来完成将程序中的面向对象的数据存储到关系型数据库的工作。这么做,自然编程的效率不高,并且非常容易出错。但是,不可否认,这也是一种可以选用的方式。
从另外一个方面来看,由于我们前面已经解决了数据的映射问题,因此,在数据的存取方面是非常有规律的,我们完全可以让这个工作通过框架来执行。这样,我们一方面可以简化很多同数据库交互方面的代码编写工作量,能够减少出现Bug的几率,另一方面,由于框架封装了不同数据库之间的差异,使得我们在编写程序的时候,不用考虑不同数据库之间的差异,而将这个工作交给框架去做,实现软件的后台数据库无关性。
在这个部分,以下两个部分的类会显得特别重要:
◆对象--关系映射的分析类,能够通过既定的方案完成对象--关系的映射,确定数据存取方案
◆数据库操纵类:根据映射关系,将数据准确的存储到数据库中,并且封装不同数据库之间的差异。
这个部分的操作过程,可以用图大概的表示如下:
在J2EE中,这个部分比较典型的就是EntityBean中的CMP。由于在BMP中,同数据库的交互部分需要通过手工编写代码的方式来实现,因此,很难享受到容器带来的便利,只是由于EJB2.0以前的标准,CMP的功能,包括映射能力、实体关系模式等方面的功能比较弱,所以,在很多时候,我们不得不使用BMP。现在,EJB2.0,在这个方面的功能已经非常强大了,我们完全可以享受容器带来的便利,而将大部分精力放在实现更加复杂的业务逻辑方面了。 在JDO中,您同样可以通过PersistenceManager来实现同样的目标,例如,您想把一个Customer对象保存到数据库中,可以采用类似于下面的代码:
Customer customer=new Customer(……); PersistenceManager PM=PMFactory.initialize(……); Pm.persist(customer);
代码同样非常简明和直观,没有一大堆数据库操纵的代码,也不容易发生差错。
Websharp的方案
Webshap为数据存取的类定义了IEntityDAO接口,该接口的定义如下:
public interface IEntityDAO { void InsertEntity(EntityData entity); void UpdateEntity(EntityData entity); void DeleteEntity(EntityData entity); EntityData FindByPrimaryKey(object KeyValue); }
对于每一个实体类,可以通过扩展这个接口来实现数据访问的类。但是,由于这个接口没有提供任何实现方法,因此,到具体每个实现类的时候,如果是直接扩展自这个接口,实现的代码还必须手工填写。为了提高开发效率,减少代码编写量和出现Bug的可能性,框架提供了AbstractSingleTableDAO和AbstractMultiTableDAO.cs类,这两个类扩展自IEntityDAO,分别实现了针对单个数据库表和多个数据库表的数据库访问方法,并且,实现了IDisposable接口。这样,我们在实际编写代码的时候,只需要继承自这两个类就可以了。
例如,Customer类的数据存取类可以定义如下:
public class CustomerEntityDAO:AbstractSingleTableDAO
然后,就可以在代码中这么使用:
Customer customer=...... using(CustomerEntityDAO CDO=new CustomerEntityDAO()) { CDO.UpdateEntity(customer); }
更加一般的,Wensharp也提供了PersistenceManager类,可以用于将EntityData中的数据存入数据库。这个类包含了两个方法:PersistEntity和DeleteEntity。如果不想为某个实体类编写专门的DAO类,那么,也可以使用这个类来操纵实体对象。不过,目前,只支持映射成单个表的对象的自动存贮。下面是一个例子:
PersistenceManager pm=PersistenceManager.Initial(); pm. PersistEntity(entity);
|
版权所有:中国教育和科研计算机网网络中心 CERNIC,CERNET,京ICP备15006448号-16,京网文[2017]10376-1180号
关于假冒中国教育网的声明 | 有任何问题与建议请联络:Webmaster@staff.cernet.com