数据封装在vc中的应用
1.前言
在vc的应用程序中,经常要涉及到数据库的操作。如果是很简单的应用,vc还算应付的过去,而对于稍微复杂一点的数据应用,vc开发出来的应用程序就需要编写大量操作数据库的代码,这些代码重复率高,操作com类型的数据,很容易出错。
虽然VC6和VC7中有开发数据库应用的向导,它把数据表封装成类,但这些向导只能在文档类型的应用中采用,如果有多个表,并且有可能需要反复的修改,它就很难满足要求。还有最重要的一点,vc中自带的数据表封装类,是针对odbc等数据连接方式的,它是老套的c/s方式的应用,现在大多应用都是基于多层设计的,数据库的连接管理由中间件管理,这种方式已经不能满足要求。
下面我们将介绍一种简单、广泛、实用的数据库的封装方案,所有的讨论是基于vc6的oracle数据应用,但它不仅限于这些平台,只要稍做修改,同样适用于java下的数据封装。
2.数据封装的规范
在进行封装之前,首先要制定数据封装的规范,说明封装的层次结构,进而才能编写程序。
规范1:每一个数据表或者视图都在VC中建立一个类,该类是数据表或视图的一个映射,它的不同类型的成员变量保存数据表或视图字段的值,该类的一个对象对应数据表或者视图的一条记录。
规范2:每一个数据表的类都是继承于CDataTable类的;每一个视图的封装类都是继承于CDataRec的,CDataTable继承于CDataRec,CDataRec继承于CDataModule,如下图(以用户信息表Yhxxb和用户信息表视图Yhxxb_v为例):
数据封装类中各类的说明:
Ø CDataModule是数据库操作的封装类,它作为一个通用类可以单独使用,在上图中它作为保护型基类,是因为数据封装类CYhxxb只能够调用CDataRec层以上的已经封装好的函数,而不能直接调用CDataModule类的成员函数直接和数据库交互。
Ø CDataRec是一个十分关键的类,保存了查询的结果集RecordSet,声明了FillAllField虚函数,利用C++的多态性,在此处调用不同子类的FillAllField函数把查询的结果数据组装到不同的子类对象中。
Ø CDataTable封装了数据表的一些操作,包括增、删、改等。
Ø CYhxxb封装了对数据表yhxxb的操作,它可以对其进行增、删、改、查询。
Ø Cyhxxb_v封装了视图Yhxxb_v的操作,它可以对其进行查找。
3.数据封装的优缺点
按照上面的规范进行数据封装的优点如下:
Ø CDataModule封装了所有的数据库的操作,它把数据库的操作全部规范起来,整个程序统一由它和数据库交互,使用简单,如果数据库选型改变,或者程序的结构有两层改为三层,仅仅修改该类即可,增加了程序的可移植性。
Ø 层次结构清楚,条理清晰,不同的类负责不同层次的操作,除了最终的表和视图的类,其它的基础类很容易修改。
Ø 最终的类是由程序自动生成,修改也十分容易。
Ø 不容易出错,数据是作为类来出现的,调用类的成员变量远远比查询数据库更加简单,编写的代码更少。
Ø 提高了设计的效率,只要在case studio(后面将详细介绍)中完成了数据库设计,就可以自动的生成数据库脚本、数据库设计文档、数据关系图、数据封装类,使快速程序设计成为可能。
但是,数据封装也存在一些缺点,它自动生成所有的数据表和视图的封装类,项目中包含很多类,查找一个类较为费时,另外编译的程序也较大。不过,在vc中可以利用字母索引查找各个类,或者在自动生成的类前面加前缀,基本不会影响它的易用性。
4.数据库的设计规范
4.1数据表的设计规范
要做数据封装,需要对数据表的设计做如下的规定:
1. 数据库的各个表格必须包含一个为number类型的Id字段,该字段唯一确定一条记录;
2. 该Id字段来自一个序列,假如表的名称为Yhxxb,该序列的名称为seq_yhxxb_id,CDataTable的Post函数中通过调用类似的语句select seq_yhxxb_id.nextval from dual找到新记录的Id。
3. 数据表之间的主外键关系需要建立,同时需要在数据库这一层来明确主键删除后子表如何处理,通过书写触发器来维护这些数据之间的关系。
4. 在数据库层要实现数据表的级联更新;
4.2视图的设计规范
视图的Sql语句的示范格式:
示例1:Create view abc(a,b,c,d) as select a , b ,(select y.cc from y where y.c=x.c) as c ,d from x;
示例2:create view abc as select x.a , x.b ,(select y.cc from y where y.c=x.c) as c ,z.d from x , z where x.c=z.c;
具体的要求说明如下:
1. 如果主select语句的from中有2个表,要按照示例2的规范来写,即select中的每个项目(如x.a)中指明是来自于哪个表的;
2. 视图的命名规则,主表名+”_v”;
3. select查询中,只有具有子查询的项目才能够使用as;
4. 只支持最基本的查询,其它的查询如sum,count函数的视图,应该检查生成的类,并且手工修改出错的内容;
5. 视图中应该有一个Id字段,该字段是来自于主表的id字段;
6. 子查询中,应该保证中间没有”,”;
7. 如果在项目中没有写表名,如示例1,则主查询的from语句中只能有一个表;
8. 暂不支持表的别名如from a xxx,b yyy的查询;
9. 仅仅支持两级视图。
5.case studio的应用
5.1 Case Studio简介
Case Studio是捷克人设计的数据库开发利器,它的理念是Create database structures faster and easier!越来越多的大公司和机构采用它,详情请参看http://www.casestudio.com。
该工具可以完成如下的功能:
Ø 进行可视化数据库设计,每一个Entity代表一个数据库表,可以快速的建立各种数据关系主外键等;
Ø 能够检查数据库设计的正确性;
Ø 自动生成详细的rtf或html格式的文档;
Ø 自动生成数据库创建的脚本;
Ø 支持脚本js或者vb脚本来访问各个Entity,本规范中生成C++类就是通过js脚本实现的;
Ø 能够把整个数据设计存储为Xml格式,可以书写其它程序来利用其数据;
Ø 能够从不同类型的数据库中解析出各个Entity;
Ø 支持多种数据库,并且能进行不同数据库的转换。
5.2 case studio中的脚本
支持js或vb脚本是该数据库工具的一个吸引人的地方,正是基于这一点,我们才能够轻松的生成基于自己规范的数据表和视图的封装类。下面简单介绍如何来书写脚本:
1) 点击按钮Edit Templates,打开模板编辑器。
2) 选择分支Events->User-defined system templates,点右键增加一个节点,按照如下图的内容来设置:
3) 在text页面输入你自己的js脚本,js脚本有固定的格式,必须有一个Main函数,详情可以在Case Studio的网站上下载示例程序,页面如下:
4) 重起case studio,就可以看到多了一个adds-in菜单,点击自定义函数的项目,就会弹出脚本的执行窗口,点击Run,会在Log里面生成程序输出的内容。
下面是利用该脚本生成的Yhxxb封装类:
class CYhxxb : public CDataTable
{
private:
;//name TypeName TypeId Length
CString m_Yhm ;//用户名 Varchar2 20 20
CString m_Yhzwm ;//用户中文名 Varchar2 20 20
CString m_Mm ;//密码 Varchar2 20 20
private:
int C_Yhm ;
int C_Yhzwm ;
int C_Mm ;
public:
CYhxxb():CDataTable("Yhxxb")
{
C_Yhm = 20 ;
C_Yhzwm = 20 ;
C_Mm = 20 ;
Find("");
}
~CYhxxb()
{
}
void FillAllFld()
{
BeginRead();
SetYhm(GetFldAsCString("Yhm"));
SetYhzwm(GetFldAsCString("Yhzwm"));
SetMm(GetFldAsCString("Mm"));
SetId(GetFldAsint("Id"));
EndRead();
}
void SetFldDefault()
{
SetYhm("");
SetYhzwm("");
SetMm("");
}
CString GetYhm()
{
return m_Yhm;
}
void SetYhm(CString pi_Yhm)
{
CheckRecStatus(FALSE);
if(pi_Yhm.GetLength()>C_Yhm)
{
ThrowZhException("Yhm字段只能够接受小于20的字串!");
}
m_Yhm = pi_Yhm;
}
.
.
.
};
6.总结
本文介绍一种广泛的数据封装方法,它属于DIY的范畴,是一种框架设计,具有通用性,你所做的只是进行一次开发,尔后尽管到处引用。如何封装这些类,本文只是给出了较为简单的介绍,旨在抛砖引玉,你需要什么样的设计,马上行动吧!