标题:VFP学习、开发漫谈 (四)
只看楼主
liuxingang28
Rank: 11Rank: 11Rank: 11Rank: 11
来 自:山东济南
等 级:贵宾
威 望:47
帖 子:649
专家分:2156
注 册:2014-2-7
结帖率:96.77%
已结贴  问题点数:10 回复次数:13 
VFP学习、开发漫谈 (四)
今天,与大伙儿聊一聊与表有关的话题。

VFP 的表分自由表和数据库表,由于数据库表与自由表相比,优点太多,而缺点几乎忽略不计,所以强烈建议用户使用数据库表。概括起来说,数据库表的优点有:可设置长表名、长字段名、字段标题、字段级规则、格式掩码,还可设置参照完整性,可支持事务处理,可通过数据库事件提高表的安全性……

尽管数据库表可设置长表名和长字段名,但不建议用户这么做,字段名还是不超过10个字符为好,长表名保持与表名相同为好。原因有二:一是若数据库未打开或当前打开的数据库不是要引用的数据库,则长表名和长字段名无效;二是一旦将数据库表转换成自由表,则字段名就会被截短成10个字符,搞得面目全非。

有用户可能问:“字段名不超过10个字符是不是太短了?”。其实一点儿也不短。你将字段名设为纯中文名称就行了。VFP 对中文字段名的支持非常好,这一点尽可放心。将字段设为中文名称还有一个好处,就是在显示字段名时不用再设置字段标题(Caption)了。有些用户喜欢将字段名设为简拼,但其可读性较差,每次引用时还得猜字段名的含义。

有用户可能认为,纯中文字段名违反了微软的命名规范。微软确实建议在字段名前加上数据类型字符。但每个人都有自己的使用习惯。下面是我在程序开发过程中遵守的规范:

1. 表名和字段名采用纯中文,且字段名不超过5个汉字
2. 对于 Local 变量,在变量名前加数据类型字符(小写),不加作用域字符,因为我们使用的变量,绝大部分是 Local变量,无需指定作用域,如:cName,nCount,lError
3. 对于 Private 变量,在变量名前加作用域字符 p 和数据类型字符,如:pcTitle
4. 对于 Public 变量,在变量名前加作用域字符 g 和数据类型字符,如:gnHandle,gnUserId,gcUserName
5. 对于常量,采取全大写格式,如:#DEFINE CR CHR(13),其中:CR 表示回车,常用于字符串的换行显示
6. 对于数组,在数组名前加 a,如:LOCAL aSum[10]
7. 对于没有特殊含义的计数变量,命名为 i 或 j,如: FOR i = 1 TO 100
8. 对于自定义函数中的形参,在参数前加字母 t 和数据类型符,如:tcType,tnCount,tdDate
9. 对于对象变量,在变量名前加字母 o,如:SCATTER NAME oEmployee,oCtrl = THISFORM.txtName
10 对各类表单控件,严格按照微软的命名规范,在控件名前加由3个字母组成的类型符,如:txtName,lblCaption,cboType
   ……

只要遵守了以上规范,可有效避免名称冲突。当然,以上仅是本人的编程习惯,仅作参考。

每个表都有一个记录指针,你可以将它理解为 RECNO()。要想完全掌握它,还真不那么容易。与记录指针相关的函数和命令有:GO,SKIP,RECN(),RECCOUNT(),BOF(),EOF()等。

问你一个简单的问题:对于一个刚建立的空表,其记录号是多少?很多人可能回答:0,正确的答案应该是:1。你可以这么理解:空表时,EOF()=.t.,而EOF()=.T.时,记录号是总记录数加 1。现在总记录数是 0,所以记录号 = 0+1 = 1。

BOF()=.T.与 EOF()=.T.有很大的不同,需要特别关注,具体如下:

1. 当前记录是表的最后一条记录,若再 SKIP,则 EOF()=.T.,RECNO()=RECCOUNT()+1。若此时引用字段的值,则显示为空白(字符型字段)或 0(数值型字段)。此时,Replace 或 Delete命令对当前记录无效。若再 SKIP,则系统报错。

2. 当前记录是表的第一条记录,若再 SKIP -1,则 BOF()=.T.,RECNO()仍为1。若此时调用字段的值,则仍显示第一条记录的值。此时,若发出 Replace或Delete命令,则是对第一条记录的修改或删除,并自动设置BOF()=.F.。当BOF()=.T.时,若再SKIP -1,则系统报错。

从上面的描述可以看出,在使用 SKIP 移动记录指针前,一定要判断 BOF() 或 EOF()的状态,否则,可能引发系统错误。

对于BOF()我是这么理解的:BOF仅是一个标记,与它对应的记录是表的第一条记录。当BOF()=.t.时,若SKIP,则转向第2条记录。对于EOF(),可以把它理解成表尾部的一条空白记录和一个标记。当EOF()=.t.时,若SKIP -1,则转向表的最后一条记录。

SKIP 命令还有一个有趣的现象,当BOF()=.F.时,可以 SKIP -100000 而不出错,仅使BOF()=.T.;当EOF()=.F.时,可以 SKIP 100000 而不出错,仅使 EOF()=.T.。(这里的100000仅代表一个很大的值)

假设要删除记录号为 5 的记录,我们不需要先 GO 5,再 Delete,只需要 Delete Record 5 即可。

VFP 的很多命令都可以设置范围(ALL/REST/NEXT n/RRCOED n),当省略范围时,这些命令都有自己的默认范围,并且默认范围受条件子句的影响。

以 Replace 命令为例:

1. 省略范围和条件时,默认范围是当前记录,即 Next 1
    Replace 工资 WITH 8000    && 把当前记录的工资替换为 8000,命令执行完成后仍为当前记录

2. 带 FOR 条件时,默认范围是所有记录,即 ALL
    Replace 工资 WITH 8000 FOR 部门='财务处'    && 将所有财务处员工的工资设为8000,运行完毕则EOF()=.T.

3. 带 WHILE 条件时,默认范围是 REST。一般使用 WHILE 条件时,都和索引排序有关。
    * 仍以上例,将财务处员工的工资设为8000
    USE 工资表 ORDER 部门
    SEEK '财务处'
    REPLACE 工资 WITH 8000 WHILE 部门 = '财务处'    && 运行完毕则记录定位到下一个部门或表尾

4. 当既有FOR条件又有WHILE条件时,WHILE条件优先,默认范围仍是 REST
    * 仍以上例,将财务处姓刘的员工的工资设为8000
    USE 工资表 ORDER 部门
    SEEK '财务处'
    REPLACE 工资 WITH 8000 WHILE 部门 = '财务处' FOR 姓名 = '刘'    && 与例3一样,运行完毕则记录定位到下一个部门或表尾
   
建议用户对上述实例验证一下,所谓“实践出真知”吗。

VFP 表的安全性是它的弱项,但可以通过以下方法加以改善:

1. 将存放数据表的文件夹设为“隐藏共享”,即在共享名前加 $,这样,共享名称就不会暴露在“网上邻居”中
2. 启用数据库事件,在打开表之前判断口令变量(如:gcPass),若口令正确则返回.t.,数据表可正常打开,否则禁止打开。

具体步骤:

1. 打开数据库属性窗口,选定“Set Events On”


2. 从事件列表中选择“BeforeOpenTable”,单击右下角的“Edit Code”按钮,输入以下代码:

PROCEDURE dbc_BeforeOpenTable(cTableName)
*Just before a table or view is opened. Return .F. to prevent table or view being opened.
    IF TYPE('gcPass')='C' AND gcPass == '12345'
        RETURN .t.
    ELSE
        RETURN .f.
    ENDIF
ENDPROC

我们要访问数据表时,只要先定义好全局变量gcPass,并为其赋值“12345”,即可随意操作数据表了。


[ 本帖最后由 liuxingang28 于 2014-2-26 19:52 编辑 ]
收到的鲜花
  • tlliqi2014-02-26 17:22 送鲜花  20朵   附言:谢谢
搜索更多相关主题的帖子: 数据库表 安全性 开发 用户 
2014-02-26 12:32
wengjl
Rank: 14Rank: 14Rank: 14Rank: 14
等 级:贵宾
威 望:108
帖 子:2175
专家分:3785
注 册:2007-4-27
得分:0 
读之,似渴饮甘露。谢谢!

只求每天有一丁点儿的进步就可以了
2014-02-26 14:26
flash7914
Rank: 2
等 级:论坛游民
帖 子:40
专家分:14
注 册:2013-4-7
得分:0 
已经习惯了看到楼主的文章,先收藏,再仔细研读。感谢。
2014-02-26 16:02
flash7914
Rank: 2
等 级:论坛游民
帖 子:40
专家分:14
注 册:2013-4-7
得分:0 
期待早日能看到关于局域网环境下编程注意事项:比如共享数据表的冲突处理、如何提高客户机数据访问速度等。
2014-02-26 16:24
cymjx
Rank: 2
等 级:论坛游民
帖 子:74
专家分:29
注 册:2010-11-9
得分:0 
期待更多的VFP学习、开发漫谈,谢谢楼主,谢谢分享。
2014-02-26 17:08
tlliqi
Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19Rank: 19
等 级:贵宾
威 望:204
帖 子:15453
专家分:65956
注 册:2006-4-27
得分:0 
谢谢分享。
2014-02-26 17:21
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
得分:10 
以下是引用liuxingang28在2014-2-26 12:32:23的发言:

……

尽管数据库表可设置长表名和长字段名,但不建议用户这么做,字段名还是不超过10个字符为好,长表名保持与表名相同为好。原因有二:一是若数据库未打开或当前打开的数据库不是要引用的数据库,则长表名和长字段名无效;二是一旦将数据库表转换成自由表,则字段名就会被截短成10个字符,搞得面目全非。
... ...
课的内容很精彩,但本堂课略有瑕疵(红色部分):库表在用USE命令打开时,所属的数据库会自动打开,不存在只打开表,不打开数据库的情况,只是该数据库不会自动成为当前库。至于长表名和长字段名,在数据库已经打开,但不是当前库的情况下,长字段名可以通过“数据库名!表名.长字段名”的形式去引用(REPLACE命令甚至可以直接引用)。比如:REPLACE field1oftest WITH 'AAA'、UPDATE test!table1oftest SET field1oftest="BBB"(该表的文件名是TABLE1.DBF);长表名在RENAME TABLE...TO...命令中不能使用,一定要使所属数据库成为当前库才能改长表名。其它命令上,只要用“数据库名!长表名”的形式即可直接引用非当前库的表文件(参考上面列出的UPDATE命令)。
2014-02-27 10:58
asdf_123000
Rank: 4
等 级:业余侠客
威 望:1
帖 子:262
专家分:203
注 册:2012-12-20
得分:0 
学习
2014-02-27 13:19
hu9jj
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
来 自:红土地
等 级:贵宾
威 望:396
帖 子:11713
专家分:43267
注 册:2006-5-13
得分:0 
暇不掩玉!
我的习惯是存放数据用数据库的表,具体操作时用自由表,操作完毕后将自由表中的数据保存在数据库表中,用这种方法来防止表损坏。

活到老,学到老! http://www. E-mail:hu-jj@
2014-02-28 08:05
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
得分:0 
以下是引用hu9jj在2014-2-28 08:05:50的发言:

暇不掩玉!
我的习惯是存放数据用数据库的表,具体操作时用自由表,操作完毕后将自由表中的数据保存在数据库表中,用这种方法来防止表损坏。

这种做法很考验记性,处理完了之后需要同步,类似于Oracle中的COMMIT事务提交。
2014-02-28 08:41



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-427692-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.240415 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved