FireBird企业解决方案编程规范

FireBird企业解决方案编程规范

帖子hwc 于 2007-12-26 9:05


对象命名规范

建立数据库对象(表、字段、存储过程、变量等)时,对象名称一律大写,一般情况下不许使用单词或拼音的缩写,必须用全拼或整个单词,同时多个词之间用下划线分割。
例“单位名称”字段合理的命名规则是DAN_WEI_MING_CHENG、DAN_WEI_MC或DEPART_NAME、DEPARTMENT_NAME皆可,下面的命名都不合理:
DWMC、DN、DepartmentName、DANWEIMINGCHENG
这种方式的来由是,SQL语言默认状况下不区分大小写。如果在对象名称中用了小写,将迫使大型数据库变成区分大小写的模式,那么SQL语言也就变成了严格区分大小写的模式,并且,对象名必须加双引号,带来非常多的不便,所以规定全部大写。
在很长的数据库对象列表中进行查找,最好对象名称非常的显眼。实践证明,缩写名称非常隐晦,容易混淆,阅读很困难。而下划线加全拼法最为容易阅读,创建对象最便捷。

注意 绝对不要使用中文对象名。尽管SQL Server等少数数据库支持这样做,但我们这里却不推荐这样做。主要原因有两点。
一、这样做使源代码数据字典的工作被数据库平台宽字符对象名功能顶替了,从而使数据字典这个重要环节容易被忽略。
二、数据库丧失了可移植性
三、针对这些对象的SQL语句也脱离了标准SQL。

注意 对于一些约定俗成的缩写,或者是开发团队中众人皆知的习惯性缩写,可以用到命名中去。例如MC代表“名称”,ID代表“编号”等。

注意 命名时,名称的字面意思一定要具体化,避免使用概括性的抽象的词。
如:进入日期应该为 ENTER_DATE或JIN_RU_RI_QI,而不应该是DATE或RI_QI

注意 命名时,要绝对避免对象名称和SQL关键字、数据库平台关键字名称相同。例如:表名、字段名都最好不要起名为SELECT, SUM, TYPE, FROM, DATE, TIME等。如果能够充分的以“具体化的”原则去命名,一般就可以避免这种现象。

注意 一般情况下,在英语和拼音之间,更推荐拼音命名法。因为拼音名称的阅读速度和大脑敏感程度要高很多,数据字典的翻译也减轻了不少的负担。一味使用英语单词,遇到生偏词汇的翻译问题,往往需花费一定的时间查资料,进而造成开发过程的中断。将常用单词和拼音结合起来命名也不失为一种好的命名方法,这样获得的可读性也不错:BU_MEN_KEY,EQUIP_MING_CHENG。
另外,在日方人员密切关注技术的项目(如琳得科)中,日方人员希望也能介入数据库结构的设计评审,乃至于他们自己打算对系统进行拓展开发,那么这种情况下就最好用英文字段了。

主键、外键创建策略
任何表都必须建立Primary Key。如果不是一个特殊情况,所有表的主键字段都由一个自增长型的整数字段来担当,其名称一般叫XXX_KEY,用这种方法来尽量避免使用联合主键(为了使开发工具端能够顺利的通过触发器识别自增长字段关联的生成器,所以,在创建自增长字段时,还要创建相应的触发器)。在这种主键设计策略中,隐含着一个很深的道理,那就是“将业务逻辑和物理逻辑脱离开”的原则,实体的业务逻辑并不直接运用到真实的物理逻辑实现上。以单据表作为一个典型的例子,单据往往具备着一个不可重复的“单据编号”,一般它的数据类型是一个几十字节的字符串,它相当于是“单据”这个实体在业务逻辑上体现出来的主键。而在这里的规范中,却并不以这个字符串编号为真正物理上的主键,而是采用一个自增长的KEY取代它成为真正的物理上的主键。以此为基础,表与表之间的关联也同样以一个单独整数字段进行关联,这个字段对于主表,一般就是主表的主键字段。在外键的创建中,一般也尽量避免多字段关联的联合外键。在FireBird数据库中,这种设计方式利用了FireBird特有的生成器(Generator)机制来实现。在创建外键时,一般都将外键的cascade delete打开,利用数据库的级联删除功能达到了自动删除从表记录。
相关的IBExpert界面如图:
11.jpg
11.jpg (75.71 KB) 被浏览 430 次

1、索引的建立
要为可能频繁发生的检索的条件组合建立相应的索引。如果定义了主从表的外键关联,那么系统会自动创建所需的索引。但针对不同的数据类型,索引的执行效率也是不同的。对于复杂的查询,可以通过plan子句告诉服务器采用怎样的索引进行数据检索,格式如下:
Select语句
PLAN(
表名1 INDEX(索引名称),
表名2 INDEX(索引名称)
)
2、字段长度的设定
相对于业务可能的最大长度应该留有0.5至1倍的余量
3、触发器的应用原则
触发器应该谨慎使用。一般触发器使用的场合是与客户端无关的数据自动计算、自动操作、自动维护数据完整性等才用触发器。如果程序涉及到用户界面显示的自动计算和其他自动机制,那么这种情况就不适合用位于服务器端的触发器了。
开发工具端编程规范
1、传统的Delphi代码习惯认为:“应建立DataModule来盛放数据访问元件,而不应将数据访问元件直接放到Form上面。这主要是使代码模块化、清晰化,使数据处理和访问与界面代码分离,同时体现一定程度的封装。DataModule应作为天然的功能实体,各种数据库相关的操作应编写成为DataModule的成员函数”,但是目前新的方法却有所不同,新推行的风格要求,首先要把数据库代码模块划分为两类,第一类是和可视化控件、数据感知控件直接关联的代码和数据访问控件;第二类是后台执行的、不直接和界面控件相关联的代码和数据库控件。对于第一类数据访问控件和代码模块,都应该合并到界面所在窗体中,和界面要素融为一体。对于第二类模块,也就是不与界面直接关联,但又会频繁的被不同的其它业务实体调用的模块,则应在独立的DataModule中作为函数来实现,并体现出合理的封装性。在这里,DataModule一般都用Form来充当,这样,DataModule本身可在调试的时候作为窗体显示出来,也可充当接收消息的实体。
2、在SQL语句不是很多的情况下,应避免在代码中书写动态SQL语句,特别是对于把数据显示界面相关联的Select语句更不推荐使用动态SQL,而是要将不同的语句放在不同的Query元件中,而且将查询控件的字段实体化,这样,代码就会更加直观,设计期实例化的字段对象也能使开发过程更加倾向于静态化属性设定,从而避免了繁琐的动态对象通过代码设定属性。一般情况下,数据集一旦确定了访问的内容,最好在设计时将Field对象加入进DataSet中。这样不仅利于在设计时定制化设置Field的属性、事件,还有利于字典化管理Field对象。单个数据集组件在关闭状态下耗费资源约4k字节,一般的场合使用很多Query元件并不会造成太多的资源的浪费。
3、数据集元件不用时应及时关闭。
4、执行条件查询SQL时,应尽量使用参数查询,而尽量不用动态SQL语句。例如:
Aquery中的SQL语句:
Select * from atable
where adate=:adate
应该是:
procedure TForm1.OpenIBQuery1(PERSON_KEY : Integer);
begin
IBQuery1.Close;
IBQuery1.ParamByName('PERSON_KEY').AsInteger := PERSON_KEY;
IBQuery1.Open;
end;
而不应该:
IBQuery1.Close;
IBQuery1.SQL.Text:=
'select * from HUMAN'#13#10
+ 'WHERE ( PERSON_KEY = ' +IntToStr(AKey)+')';
IBQuery1.Open;

5、对数据集循环检索时,应使用While循环。
标准的写法是:
12.jpg
12.jpg (75.09 KB) 被浏览 433 次


不要使用for循环。RecCount只有部分文件型数据库访问元件才支持,很多数据库组件根本就不支持RecCount方法。对数据集的循环能够通过dsl或dsl2两个代码宏来展开,该宏有一个参数,就是数据集名称。
5、字段的访问方式
访问DataSet的字段,有多种写法,应该用到不同的地方。
1) AdataSet.FieldByName(‘AFieldName’).AsDataType
2) AfieldObjectName. AsDataType
3) AdataSet.FieldByName(“AFieldName”).Value
4) AfieldObjectName.Value
5) AdataSet[‘AFieldName’]
6) AdataSet.Fields[n].Value
FieldByName方式可移植性和灵活性、可读性上面好一些,但性能略差;直接书写AfieldObjectName性能好,但灵活性略差。两种方式皆可用于开发中。为了提升代码编写的速度,目前比较推荐AfieldObjectName的写法,因为这种访问字段的方式能够充分的借助开发环境代码提示的帮助使字段的对象名称的寻找比较迅速。

数据库程序的代码结构
1、 功能模块的编写应体现封装原则。
a) 代码对控件的封装
这一情况最典型体现在编写Query控件的包裹函数了。执行参数查询,并非在调用该功能的Context中直接书写该Query控件的操纵代码,而应把细节相关的过程封装到一个函数中,通过函数去配置、执行SQL语句:
13.jpg
13.jpg (42.52 KB) 被浏览 425 次

这种函数可以是模块的成员函数,也可以是成员函数的局部函数
除了针对控件的直接封装以外,还可能对复杂的功能模块进行封装。
b) 用存储过程将一部分功能封装在服务器端
有一些程序功能比较适合于数据库端实现,这类功能即可用存储过程来实现。包含两种,其一是进行单纯数据处理的存储过程,其二是返回数据集的存储过程。
c) 不同的业务功能模块应进行合理的抽象,以窗体、DataModule、类的形式根据业务逻辑演化出不同的实体对象。应避免把多个没有密切关系的业务功能挤到一个实体中编写,造成代码的无谓的复杂化;同样也应避免切分不当所导致的一个模块需要繁琐的调用其它模块的内部内容。业务实体之间应该尽量维持清晰、单向的调用关系。
2、 数据集对象的建立方法
a) 对于需要在内存中持久存在的记录集,例如和数据感知控件持久连接的记录集,一般使用ClientDataSet/Provider/IBQuery的模式。对于非持久性的数据集,则应该使用Query控件直接取得数据,使用完毕后关闭Query即可。
b) 一般情况下不推荐使用IBTable控件。除了针对文件数据库外,一般的网络数据库都不推荐使用XXTable控件。
c) 调用不返回记录集的存储过程可以使用IBStoredProc控件。但是,如果调用的存储过程将返回记录集,则应使用IBQuery访问该存储过程,并且可以连接ClientDataSet将返回的数据持久化。
d) ClientDataSet/Provider/IBQuery的模式下,Provider的UpdateMode属性应该为upWhereKeyOnly,同时,在Query控件中的关键字字段对象的ProviderFlay应该把pfInKey打开,这样,Provider进行数据更新的时候,将用关键字字段进行定位,增加了定位效率。
e) ClientDataSet/Provider/IBQuery的模式下,IBQuery可以带有参数,这样,相当于是带参数的可更新的记录集。设定参数打开ClientDataSet的方法是:
14.jpg
14.jpg (56.88 KB) 被浏览 431 次

f)
这也是一种包裹函数风格的封装,是先关闭ClientDataSet,然后设定Query参数,然后再打开ClientDataSet。这样的包裹函数也能通过开发环境提供的向导生成。
g) 对于需要频繁Locate,或进行Lookup的ClientDataSet,应在ClientDataSet控件上建立客户端索引,索引的字段和Lookup的字段相对应。建立索引的方法是设定ClientDataSet的IndexDefs和IndexFields两个属性。
3、 自增长字段的建立
建立表的时候,在IBExpert中通过打开字段的AutoInc属性设定某字段是自增长字段后,同时建立相应的生成器和触发器;在客户端通过设计器的右键菜单建立ClientDataSet指向该表后,开发环境会自动切换到代码编辑器中,并且会生成AfterInsert事件,此时粘贴剪贴板,即可粘贴出生成自增长整数的代码,它是调用一个客户端GenID函数的代码,该函数需要人为的去实现,它通过调用SQL语句来得到服务器端生成器的值并使之加1:
Select gen_id(AGenerator,1) as id from rdb$database
一般情况下,一个表对应着一个生成器。但是在某些情况下,可能多个表共用一个生成器,也可能一个表用多个生成器
4、 搜索的实现
SQL语句的条件如果是
(FIELD1 containing 'AStr')
OR
(FIELD2 containing 'AStr')
即是在Field1和Field2中搜索字符串’AStr’。同理,在若干个字段中进行搜索就是用OR把若干个CONTAINING条件连接起来。
如果需要搜索以什么打头,或者以什么结尾则对应的SQL语句的Where条件是
AFIELD LIKE ‘astr%’ 或者 AFIELD LIKE ‘%astr’
5、 数据分页机制
对于业务中不断快速增长的数据场合而言,程序设计中的一个首要数据分页角度就是基于业务逻辑数据分页,这里最典型的就是根据时间分页。因为往往在企业的业务管理中,不同时间区间的数据之间一般都保持着相当的独立性,完全不必要同时打开。所以大多数场合的软件都以单个日期或财政月为分页单位。是通过条件查询来实现的,查询的条件建立了相应的索引。
但在FireBird数据库中,还提供了一个能用于数据分页的特性,那就是select first n skip m ...的语法。它相当于把服务器端的数据集从第m+1条记录开始,取最多n条记录。该语句可用于ClientDataSet/IBQuery中,作为参数SQL执行,m和n都是query的参数,随着界面上翻页按钮的点击,对参数赋值刷新记录集。

posted on 2009-01-04 20:16  费戈  阅读(499)  评论(0编辑  收藏  举报

导航