XCodeFactory

C#编程爱好者
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

XCodeFactory3.0完全攻略--IDBAccesser

Posted on 2005-09-13 12:06  C#编程爱好者  阅读(1338)  评论(0编辑  收藏  举报
    IDBAccesser接口是XCodeFactory生成的数据层代码的核心部分。要了XCodeFactory生成的数据层,就必须了解 IDBAccesser接口。
    如果你看过上一节的示例、并研究过生成的代码,你一定会发现,所有对数据库的访问操作都是通过IDBAccesser接口来完成的。比如,上一节插入一个学生到数据库中大致是这样的:
private IDBAccesser dealStudent = DataEntrance.CreateDBAccesser(typeof(Student)) ;

Student a_student 
= this.CreateStudentFromTextbox() ;
this.dealStudent.Insert(a_student , null) ;
    
    其中的成员变量dealStudent就是IDBAccesser接口的引用。在看看StudentDealer.cs文件中的代码,会发现三个类:StudentDealer、StudentSqlDealer、StudentOleDealer,它们的继承关系一目了然。其中StudentDealer直接从IDBAccesser继承,并且它是一个抽象类,之所以设计为abstract,是因为它是与数据库类型无关的,而与数据库类型相关的信息都封装在几个虚拟方法中了,比如GetDBTypeElementFactory方法,而与数据库类型相关的实现类,如StudentSqlDealer和StudentOleDealer将会覆写这些虚拟方法。这样做的好处是,如果增加对其它数据库类型的支持,只需要增加一个派生类,比如需要支持Oracle,那么就增加一个StudentOracleDealer,而这个类的实现也是非常简洁的,只要覆盖基类StudentDealer的四个虚拟方法即可。

    下面给出以IDBAccesser为核心的继承体系图:

    可以看到,IDBAccesser从另外三个接口继承。你对数据库表的所有操作基本上都包含于这三个接口中。这三个接口分别是:基于对象操作的查询接口IDBAccesserQuery,基于对象操作的命令接口IDBAccesserOrder(添加/删除/修改)、和基于关系操作的关系型接口IDBAccesserRelation(操作DataSet、DataReader ,基于关系操作)。下面将展示这三个接口的外貌。
(1)IDBAccesserQuery接口
/// <summary>
    
/// IDBAccesserQuery 为执行sql查询接口
    
/// </summary>
    public interface IDBAccesserQuery
    {
        
bool     ReviseAObject(string where_str ,object target )  ;//使用数据库内容来更新当前对象
        object   GetAObject(string where_str) ;//if there is no condition clause ,please input ""
        object[] GetObjects(string where_str) ;        
        
object[] GetObjectsWithoutBlob(string where_str) ; //获取的对象中凡是Blob字段都未填充
        bool     FillBlobData(object obj) ;                   //填充某个对象的所有Blob字段
        DataSet  GetDataSet(string select_str) ;    
    }
   
    大家已经发现了, 查询返回的对象类型是object,而且后面的各个接口的操作也都是object类型,这种弱类型的方式是迫不得已的,因为需要统一所有数据访问类的基础接口,在.NET 1.1中没有提供对泛型的支持,所以在使用通用的object类型。
    查询的条件一般是where字句,它符合SQL语句标准。我看到很多ORM工具,都提供了自己的查询语句,那可能是为了更好的实现它自己的目的。而XCodeFactory没有这样的要求,因为标准的sql语句已经完全够用,并且可以降低使用者的上手难度--相信普通的开发人员都使用过SQL进行数据库操作。
    注意,如果没有where条件,那么参数请传入"",而不是传入null。
    GetObjectsWithoutBlob方法和FillBlobData方法是对Blob字段的延迟加载机制进行支持。比如,我们的Mentor表中需要存放每个导师的照片资料,这是一个Blob字段。在浏览导师列表的时候,如果一次把所有的Blob都读出来,无疑会浪费内存并损害访问数据库的效率。只有当用户想深入查看某个导师的详细资料时,在调用FillBlobData方法来填充该导师照片字段的数据,这样不是更好么?!
   最后一个方法 GetDataSet应该属于一个关系型操作,但是它也属于查询操作,所以就将它放在IDBAccesserQuery接口中了。

(2)IDBAccesserOrder接口
/// <summary>
    
/// IDBAccesserOrder 为执行sql命令接口
    
/// </summary>
    public interface IDBAccesserOrder
    {
        
//如果不需要事务,trans以null传入
        void Insert(object obj ,IDbTransaction trans) ;
        
void Update(object obj ,IDbTransaction trans) ;        
        
void Delete(object ID ,IDbTransaction trans) ; //ID一般为int或string类型    
        void InsertBatch(ArrayList objs ,IDbTransaction trans) ;//批插入

        
//插入对象并返回自动编号标志
        object InsertReturnIdentity(object obj ,IDbTransaction trans) ;
    }    
    
    一般,查询是与事务没有关系的,但是命令就经常会牵涉到事务,所以IDBAccesserOrder接口一开始就对事务提供了基本的支持,IDBAccesserOrder接口中的各个方法的第二个参数就是事务的引用。如果你某个命令操作不牵涉事务,那么第二个参数可以传入null。Insert和Update方法都很简单,而Delete方法中的第一个参数为object类型的ID,不知你是否还记得在XCF约定中有一条那就是每个表需要有一个主键字段,并且字段名为“ID” ,Delete方法便依赖于这个约定!ID的类型通常为数值类型(如int)或字符串。
    再看InsertBatch方法,它是执行批插入的功能。很多情况下,我们的批插入都需要与一个事务关联起来,InsertBatch方法正好简化了这个操作。请注意,InsertBatch与加for循环的Insert方法的效率是不一样的,InsertBatch的效率更高!
    最后一个方法InsertReturnIdentity方法用于主键ID是自动编号的情况。在主键是自动编号时,插入一个对象之前,该对象的主键字段ID的值是不知道的,只有插入后,这个值才确定下来。InsertReturnIdentity使你插入对象的操作一完成,即刻就可以知道数据库为该字段分配的ID值。这个功能是很有用的:)

(3)IDBAccesserRelation接口
/// <summary>
    
/// IDBAccesserRelation 为执行sql关系型接口
    
/// </summary>
    public interface IDBAccesserRelation
    {
        
//RelationAction
        int         GetRecordsCount() ;//得到表中记录的总数
        object      GetFieldValue  (string theID ,string fieldName) ;
        
object        GetFieldValueEx(string whereStr ,string fieldName) ;
        
bool        UpdateFieldValue(object theID ,string fieldName ,object newVal ,IDbTransaction trans) ;
        
object      ExecuteScalar(string command) ;
        IDataReader GetReader(
string select_str) ; //IDataReader用完后要及时关闭
    }
        如果要获取数据库中某条记录的某个字段的值,可以这样做:
string whereStr   = string.Format("where {0} = '{1}'" ,Student._ID ,"1001") ;
Student a_student 
= (Student)this.dealStudent.GetAObject(whereStr) ;
int hisAge          = a_student.Age ; 
    而使用IDBAccesserRelation接口就可以这样做:
int hisAge = (int)this.dealStudent.GetFieldValue("1001" ,Student._Age) ;
    简单多了吧。GetFieldValueEx与GetFieldValue的区别在于,GetFieldValue通过ID取出指定的对象,而GetFieldValueEx取出的是符合where字句条件的第一个对象的特定字段的值。
    UpdateFieldValue也是一样,它为更新指定对象的某特定字段的值提供了简洁入口。
    其它的界个方法就不用多说了。

    最后来看看IDBAccesser接口吧
/// <summary>
    
/// IDBAccesser 是最核心的数据访问接口    
    
/// 作者:朱伟 sky.zhuwei@163.com 
    
/// </summary>
    public interface IDBAccesser :IDBAccesserQuery ,IDBAccesserOrder ,IDBAccesserRelation
    {
        
//property
        string         ConnectString{get ;}
        
string         DbTableName {get ;}
        DataBaseType DataBaseType{
get ;}            

        
//others
        IDataPaginationManager GetPaginationMgr(string selectStr ,int page_size ,bool ascending) ;
    }
    
    IDBAccesser除了继承上述的三个接口外,还新添加了几个属相和方法。前面三个属性很容易理解,最后一个方法GetPaginationMgr用于获取分页管理器,分页管理器对数据集自动分页提供支持,关于它的详细介绍将会在本系列的“高级特性”一文中。

    到此为止,我们已经了解了IDBAccesser接口的所有内容,在熟悉了IDBAccesser接口之后,相信你可以很容易的使用XCodeFactory的生成数据层的代码了。
    为了更加简洁的使用数据层代码,请关注下一篇文章:DataEntrance简化数据访问

    XCodeFactory3.0完全攻略 目录