XCodeFactory2.0完全手册(中)

在前面的一篇文章中介绍了 XcodeFactory 生成的代码的基本结构和访问类的基本用法,我们是通过类似 IDBAccesserdealTeacher=newTeacherSqlDealer(connStr); 来得到访问类实例的,这样做有两个弊端:

(1) 如果我们在某个其它的类中只需要使用一次访问对象,那我们也要new一个出来。这样项目中到处都会看到IDBAccesserdealTeacher=new***(connStr);的身影。而且同一类型的访问类的所有实例都是一摸一样的,所以整个项目中,对于每一个访问类,只要一个实例就可以了。

(2) IDBAccesserdealTeacher=newTeacherSqlDealer(connStr);这样的语句,使我们的项目与具体的数据库类型(例子中是SqlServer数据库)绑定在一起了,如果需要更改数据库类型,我们需要更改所有这样的地方。

对于问题(1),大家都知道通过Singleton模式就可以解决问题,问题(2)则可以通过一个工厂来解决。为了使访问类仍然能以基础的方式进行使用,我没有把访问类设计成单件模式,而是通过引入一个静态类DataEntrance来同一管理访问类实例。在使用DataEntrance解决问题(1)的同时,问题(2)也自然被解决了。让我们来看看DataEntrance的背后玄机。

前篇文章中提到的访问类的基本使用方式并没有被替代,你仍然可以按照以前的方式来使用它,而DataEntrance为我们提供了更简单的使用方式。参见http://blog.youkuaiyun.com/zhuweisky/archive/2005/07/29/439291.aspx 可以先对DataEntrance有个感性的认识,这对下面的理解会有帮助。

首先DataEntrance是一个静态类,这样我们在使用它的时候,可以直接通过类名引用其方法,而不需管理DataEntrance的实例。

其次DataEntrance需要在系统启动的时候初始化。

虽然,DataEntrance是一个静态类,但是其需要被初始化,初始化动作的目的就是设定数据库的相关信息,比如连接字符串、数据库类型等。在这里,我们需要考虑,如果在程序运行的过程中,用户更改了数据库的配置信息,那么我们的DataEntrance也应该能随其改变以适应最新的情况。为了使DataEntrance能接收这样的通知,我设计了IDataBaseInfoMgr接口,该接口发布了DbConfigChanged事件。其定义如下:

public interface IDataBaseInfoMgr
{
stringGetConnString(outDataBaseTypedbType);
eventEventHandlerDbConfigChanged;
}

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

public static bool InitializeDBAccesserFactory(IDataBaseInfoMgrdbInfoMgr,IDBAccesserFactorydbFactory)

其中,IDBAccesserFactory接口有什么用了?我们先看看DataEntrance这一示例用法:

其中, IDBAccesserFactory 接口有什么用了?我们先看看 DataEntrance 这一示例用法:
string name = DataEntrance.GetFieldValue( typeof (MobileUser), " 0 " , " Name " ).ToString();

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

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

public interface IDBAccesserFactory
{
//如果connStr经常变化,可传入null。如果是Ole,则connStr为access文件的路径。
//cachAccesser表示是否缓存创建的实例,
voidInitialize(DataBaseTypedbType,stringconnStr,boolcachAccesser);

//采用dataClassType作为参数是为了在编译时发现类型不存在的错误,比如删除了一个表及对应数据类,则相关的其它代码将无法通过编译
IDBAccesserCreateDBAccesser(TypedataClassType);
IDBAccesserCreateDBAccesser(DataBaseTypedbType,
stringconnStr,TypedataClassType);

//适用于dealer与dataclass命名空间不同的情况
IDBAccesserCreateDBAccesser(TypedataClassType,stringdealerNamespace);
}

那么,CreateDBAccesser方法是如何根据数据对象类的名字来创建对应的访问者实例的了?因为XcodeFactory生成的数据层代码有这样一个约定:如果数据对象类的名字是Abc,那么Ole的访问者就是AbcOleDealerSqlServer的访问者就是AbcSqlDealer,并且数据对象类和访问者处于同一命名空间中,所以一旦IDBAccesserFactory知道了数据对象类的类型,自然就可以根据数据库类型推倒出访问者类型,然后通过反射,就可以创建访问者实例了。

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

下面的例子是根据学生的ID找到其导师的名字,以前需要这样做:

IDBAccesserstudentDealer = dbAccesserFactory.CreateDBAccesser( typeof (student));
Studentstu
= (Student)studentDealer.GetAObject( " WhereID='001' " );
IDBAccessermentorDealer
= dbAccesserFactory.CreateDBAccesser( typeof (Mentor));

Mentormentor
= (Mentor)mentorDealer.GetAObject( string .Format( " WhereID='{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方法的参数中。

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

最后,我们需要进一步挖掘DataEntranceDataEntrance正如其名,是我们访问数据层的入口。我想使我们与数据层的所有交互都通过DataEntrance进行,而且我们也不想再关心IDBAccesserFactory了。所以我决定将一切都封装到DataEntrance的静态方法中(比如IDBAccesserFactory的初始化),这样能最大限度的方便我们的使用。所以我们在系统启动的时候,需要调用DataEntrance的初始化方法,该方法就包含了对IDBAccesserFactory初始化方法的调用。到现在为止,我们已经完全可以通过DataEntrance来完成一切的数据层的访问操作了。下面将DataEntrance主要的静态方法的声明贴出来:

/**/ ///<summary>
///DataEntrance是使用EnterpriseServerBase.DataAccess的基础入口,对XCodeFactory生成的数据层代码提供最大的支持,
///简化用户对该类库的使用。
///(1)用户必须实现IDataBaseInfoMgr接口用于提供数据库类型和连接信息。
///(2)dbFactory直接传入newXDBAccesserFactory()即可。
///(3)请确保在主窗体的构造函数中或Main方法中调用了DataEntrance.InitializeDBAccesserFactory();
///(4)凡是需要得到IDBAccesser实例的地方,请调用DataEntrance.CreateDBAccesser();
///(5)若是只需要使用IDBAccesser接口的query和order接口,可以使用DataEntrance中提供的更简单的对应方法
///</summary>

public class DataEntrance
{
publicstaticboolInitializeDBAccesserFactory(IDataBaseInfoMgrdbInfoMgr,IDBAccesserFactorydbFactory);

publicstaticIDBAccesserCreateDBAccesser(TypedataClassType);

Query#regionQuery
publicstaticobjectGetFieldValue(TypeobjType,stringtheID,stringfieldName);

publicstaticDataSetGetDataSet(TypeobjType,stringselect_str);

publicstaticobjectGetAObject(TypeobjType,stringwhereStr);

publicstaticobjectGetAObjectEspecial(TypeobjType,stringtheID);

publicstaticobject[]GetObjects(TypeobjType,stringwhereStr);

publicstaticobject[]GetObjectsWithoutBolb(TypeobjType,stringwhereStr);

publicstaticboolFillBlobData(TypeobjType,objectobj);
#endregion


Order#regionOrder
publicstaticvoidInsert(TypeobjType,objectobj,IDbTransactiontrans);

publicstaticobjectInsertReturnIdentity(TypeobjType,objectobj,IDbTransactiontrans);

publicstaticvoidInsertBatch(TypeobjType,ArrayListobjs,IDbTransactiontrans);

publicstaticvoidInsertBatch(TypeobjType,object[]objs,IDbTransactiontrans);

publicstaticvoidUpdate(TypeobjType,objectobj,IDbTransactiontrans);

publicstaticboolUpdateFieldValue(TypeobjType,objecttheID,stringfieldName,objectnewVal,IDbTransactiontrans);

publicstaticvoidDelete(TypeobjType,objectID,IDbTransactiontrans)//ID一般为int或string类型
#endregion


publicstaticIADOBaseGetADOBase();

publicstaticIDataPaginationManagerGetPaginationMgr(TypeobjType,stringselectStr,stringcomplexID_Name,intpage_size);

publicstaticITransactionHelperGetTransactionHelper();

privatestaticIDBAccesserGetDestDealer(TypedataObjType);
}

如果你只是想使用XcodeFactory生成的数据层代码,而不想关心其它的东西,那么了解一下DataEntrance就足够了,如果你想知道这些代码内部是如何工作的,还有哪些更高级的使用方法等高级内容,请关注我的使用手册(下),谢谢!

附注:关于自动生成的数据层代码.cs文件的组织

我的习惯是,为数据层建立一个目录叫做DataAccessLayer XcodeFactory生成的所有cs文件都放在这个目录下的某个子目录下。对应数据库中的每一个表(也对应一个cfp文件),在DataAccessLayer目录下建立一个对应的文件夹,这个文件夹下放有该cfp文件生成的数据对象类和访问类(可能还有自动生成的窗体类),下图是我的PoliceMonitorSystem项目中的文件结构组织截图:(其中蓝色的圈圈中的目录,是从XcodeFactory主菜单=》帮助=》获取DataAccess压缩包解压后得到的)

<shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></path><lock aspectratio="t" v:ext="edit"></lock></shapetype><shape id="_x0000_i1026" style="WIDTH: 288.75pt; HEIGHT: 442.5pt" type="#_x0000_t75"><imagedata o:title="ැ࿶ෘ࿶" src="file:///C:/DOCUME~1/ADMINI~1/LOCALS~1/Temp/msohtml1/01/clip_image001.png"></imagedata></shape>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值