XCodeFactory

C#编程爱好者
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理
    在前面的XCodeFactory3.0主界面介绍、简单示例一文的例子中,我们已经几次见到过DataEntrance的身影了,比如Main方法中的初始化代码:
IDataBaseInfoMgr dbInfoMgr = new DataBaseInfoMgr() ;
DataEntrance.InitializeDBAccesserFactory(dbInfoMgr,
new XDBAccesserFactory()) ;
    
    后面在StudentForm中,我们又是这样来获取IDBAccesser引用:
private IDBAccesser dealStudent = DataEntrance.CreateDBAccesser(typeof(Student)) ;

    实际上,如果没有DataEntrance,我们仍可以正常的使用生成的数据层代码,只不过繁琐些。比如我们可以直接获取IDBAccesser引用:
IDBAccesser dealStudent = new StudentSqlDealer(conn) ;
    这样做,有两个缺陷:
(1)代码中硬编码了数据库类型。上面代码指定了使用针对SqlServer数据库的访问者,当数据库类型发生变化时,所有类似的地方都要手动修改。
(2)即使我只是要提取某个指定对象的指定字段的值,也需要经历像下面这样繁琐的过程:
            IDBAccesser dealStudent = new StudentSqlDealer(conn) ;
            
string whereStr = string.Format("where {0} = '1001'" ,Student._ID) ;
            Student st 
= (Student)dealStudent.GetAObject(whereStr) ;
            
int age    = st.Age ;
    
    也许在得到编号为1001学生的年龄之后,就再也用不着dealStudent了,但是也不得不如此。在现实的应用中,我们会碰到很多类似的情况,如果每次都这样,未免也激怒大部分使用者。但是如果能这样,就会令使用者开心了:
int age = (int)DataEntrance.GetFieldValue(typeof(Student) ,"1001" ,Student._ID) ;
    上面需要四句代码完成的事情,这里用一句就搞定了,并且DataEntrance还解决了与特定数据库类型绑定的问题。

    从上面的叙述,我们已经可以看到,DataEntrance的主要目标有两个:
(1)将使用数据访问者的代码与创建数据访问者的代码隔离开来,这有点像抽象工厂模式的目的。如果在应用的过程中,需要更换数据库类型,只需要修改相关的配置文件中的指定数据库类型的字段即可,而程序不需重编译。
(2)最大程度的简化数据层的使用。上面的例子已经说明了DataEntrance的威力。
    
    下面我们就来看个明白,如何使用DataEntrance以及DataEntrance是怎么工作的?
首先DataEntrance是一个静态类,这样我们在使用它的时候,可以直接通过类名引用其方法,而不需管理DataEntrance的实例。
其次DataEntrance需要在系统启动的时候初始化。 
    虽然,DataEntrance是一个静态类,但是其需要被初始化,初始化动作的目的就是设定数据库的相关信息,比如连接字符串、数据库类型等。在这里,我们需要考虑,如果在程序运行的过程中,用户更改了数据库的配置信息,那么我们的DataEntrance也应该能随其改变以适应最新的情况。为了使DataEntrance能接收这样的通知,我设计了IDataBaseInfoMgr接口,该接口发布了DbConfigChanged事件。其定义如下:
   
/// <summary>
    
/// IDataBaseInfoMgr 用于向DataEntrance提供数据库连接信息
    
/// </summary>
    public interface IDataBaseInfoMgr
    {
        DataBaseType GetDbType() ;
        
string         GetConnString() ;
        
string         GetConnString(string dbName) ; //针对多数据库
        void         ActivateDbConnChangeeEvent() ; //外部通知IDataBaseInfoMgr数据库连接信息发生了变化
        
        
event         EventHandler DbConfigChanged ; 

        
bool         IsMultiDataBase{get ;}
    }

    我把该接口的引用作为DataEntrance初始化的参数传进去,这样DataEntrance就能在数据库配置信息改变时,做相应的调整了。看看DataEntrance的初始化方法的声明:

public static bool InitializeDBAccesserFactory(IDataBaseInfoMgr dbInfoMgr ,IDBAccesserFactory dbFactory );

    第一个参数就是IDataBaseInfoMgr引用,我们可以自己实现IDataBaseInfoMgr接口,其实,在使用XCodeFactory生成数据层代码时,已经给我们自动生成了一个默认的DataBaseInfoMgr.cs文件,我们可以直接使用其中定义的DataBaseInfoMgr类,但是我建议使用者最好是修改一下GetConnString方法和GetDbType方法的实现--从配置文件获取连接信息和数据库类型信息,而不是将它们写死在方法实现中。     
    第二个参数是一个
IDBAccesserFactory引用,IDBAccesserFactory接口有什么用了?为了说明它,我们可以先看看下面的代码:

string name = DataEntrance.GetFieldValue(typeof(MobileUser) ,"0" ,"Name").ToString() ;

   对DataEntrance.GetFieldValue方法, 我们传入的第一个参数是我们的数据对象类型,也就是说我们需要根据数据对象的类型来得到对应的访问类实例,这需要通过反射来完成,IDBAccesserFactory就是做这件事的,并且IDBAccesserFactory还会缓存创建过的数据访问者实例。由于反射无法穿越自定义的程序集,所以我将XDBAccesserFactory.cs放在了本地文件夹EnterpriseServerBase.DataAccess中。IDBAccesserFactory接口的定义如下:

    public interface IDBAccesserFactory
    {    
            
void Initialize(DataBaseType dbType ,string connStr ,bool cachAccesser) ;    
    
            IDBAccesser CreateDBAccesser(Type dataClassType) ;        
            IDBAccesser CreateDBAccesser(DataBaseType dbType , 
string connStr , Type dataClassType);
            IDBAccesser CreateDBAccesser(Type dataClassType ,
string dealerNamespace) ;        
    }

     那么,CreateDBAccesser方法是如何根据数据对象类的名字来创建对应的访问者实例的了?你肯定还记得XCF约定:数据访问类的名字的格式是:“数据库表名 + 数据库类型 + Dealer”,并且数据对象类和访问者处于同一命名空间中,所以一旦IDBAccesserFactory知道了数据对象类的类型,自然就可以根据数据库类型推倒出访问者类型,然后通过反射就可以创建访问者实例了。  
    对于DataEntrance的初始化,通常我们只要这样就足够了:

IDataBaseInfoMgr dbInfoMgr = new DataBaseInfoMgr() ;
            DataEntrance.InitializeDBAccesserFactory(dbInfoMgr,
new XDBAccesserFactory()) ;


    再次
IDBAccesser 接口中的方法基本上都可以在DataEntrance中找到对应的静态方法。只不过这个静态方法比IDBAccesser 的对应方法多了一个参数,这个参数就是数据对象类的类型,正如上面提到的,这个类型用于IDBAccesserFactory动态的产生访问者实例。所以,以前我们需要先new一个访问者出来,然后再进行数据访问操作,现在不用这么麻烦了。对数据层的操作,我们完全可以通过DataEntrance进行。 
    下面的例子是根据学生的ID找到其导师的名字:

             //不使用DataEntrance:
            IDBAccesser  studentDealer  
= dbAccesserFactory. CreateDBAccesser (typeof(student)) ;
            Student stu      
= (Student)studentDealer.GetAObject("Where ID = '001'") ;
            IDBAccesser  mentorDealer    
= dbAccesserFactory. CreateDBAccesser (typeof(Mentor)) ;

            Mentor mentor     
= (Mentor)mentorDealer.GetAObject(string.Format("Where ID = '{0}'" ,stu.MentorID)) ;
            
string theName     = mentor.Name ;

            
//使用DataEntrance可以这样做:
            string mentorID = DataEntrance.GetFieldValue(typeof(Student) ,"001" ,"MentorID").ToString() ;
            
string theName  = DataEntrance.GetFieldValue(typeof(Mentor) ,mentorID ,"Name").ToString() ;

      使用DataEntrance的优势很明显了,而且我们的代码完全不依赖于数据库的类型。使用何种数据库类型只需要在一个地方指定,那就是IDBAccesserFactoryInitialize方法的参数中,而这个参数的值最终来源于配置文件。 

    最后,我们需要进一步挖掘DataEntranceDataEntrance正如其名,是我们访问数据层的入口。我想使我们与数据层的所有交互都通过DataEntrance进行,而且我们也不想再关心IDBAccesserFactory。所以我决定将一切都封装到DataEntrance的静态方法中(比如IDBAccesserFactory的初始化),这样能最大限度的方便我们的使用。通过VS.NET的智能感知,你可以看到DataEntrance的所有公有静态方法,这些方法的作用一目了然,基本与IDBAccesser接口的方法一一对应。
    到现在为止,我们已经完全可以通过
DataEntrance来完成一切的数据层的访问操作了。如果你只是想使用XcodeFactory生成的数据层代码,而不想关心其它的东西,那么了解一下DataEntrance就足够了,如果你想知道这些代码内部是如何工作的,还有哪些更高级的使用方法等高级内容,请继续关注我后面的文章。

DataEntrance源代码

XCodeFactory3.0完全攻略 目录