• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

delphi中 dataset容易出错的地方

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

最近写delphi项目,用到的数据集中的dataset,一直修改exception啊,写下过程。

 

 在对数据集进行任何操作之前,首先要打开数据集。要打开数据集,可以把Active属性设为True,例如:
  CustTable.Active := True;
  也可以调用Open函数,例如:CustQuery.Open;
  要关闭数据集,可以把Active属性设为False或者调用Close函数。

其次 如果有exception的话,就要判断state,下面我列举下state的值(这样是我从网上找的)

State属性是只读的,下面列出了State属性可能的值:
.dsInactive 数据集已关闭,不能访问它的数据;
.dsBrowse 数据集已打开,可以浏览数据但不能修改数据;
.dsEdit 此时为编辑状态,可以修改数据;
.dsInsert 此时可以插入一条新的记录;
.dsSetKey 只适用于TTable和TClientDataSet,此时可以设置范围和键值,并且可以调用GotoKey函数;
.dsCalcFields 正在处理OnCalcFields事件(当字段需要指定一个值的时候促发的事件),此时不能修改非计算字段的值;
.dsCurValue 内部使用;
.dsNewValue 内部使用;
.dsOldValue 内部使用;
.dsFilter 正在进行过滤操作。 

当我看到我的项目的state为 dsInactive ,被踢我有多高行啦,然后立马改为dsedit,尼玛。但是还不管用,然后又看到方法:

如果应用程序要修改数据集的数据,必须首先进入dsEdit状态。要进入dsEdit状态,可以调用Edit。不过,调用Edit并不能保证一定能进入dsEdit状态,这还取决于CanModify属性的值。如果这个属性返回True的话,表示数据集是可以读和写的。

终于完成了,尼玛,就因为这被经理说,效率慢,该错误还是比较容易的,但是exception,就不是那么简单。下面补充下dataset的其他state的介绍:

下面的功能我是没用到的::

 

 

6.7.2 插入新的记录
  要在数据集中插入新的记录,首先要进入dsInsert状态。要进入dsInsert状态,可以调用Insert或Append函数。不过,调用Insert或Append不一定会使数据集进入dsInsert状态,还取决于CanModify属性的值。
  一旦进入了dsInsert状态,用户就可以在数据控件(一般是TDBGrid)中插入一条新的记录,并给这条记录输入数据。
  如果要通过编程来插入新的记录,就要注意Insert和Append的区别。Insert将把一条新的记录插入到当前记录的前面,而Append将把一条新的记录添加到数据集的末尾。
  插入了新的记录后,应当调用Post或在CachedUpdates属性设为True的情况下调用ApplyUpdates把新的记录写到数据集中。
  如果数据集是已建立了索引的Paradox或dBASE表,新记录将自动移到恰当的位置。
  如果数据集没有建立索引,新记录就插入到数据集的当前位置(Insert)或末尾(Append)。
6.7.3 删除记录
  调用Delete函数将删除当前记录,并且使数据集回到dsBrowse状态。如果窗体上有TDBNavigator构件的话,用户可以单击导航器上的“Delete”按钮删除当前记录。当前记录被删除后,下一条记录就成为当前记录。
  如果删除的本来就是最后一条记录,则前一条记录成为当前记录。
6.7.4 修改整条记录
  除了TDBGrid和TDBNavigator外,大部分数据控件只能工作于数据集的一个或几个字段,而不是整条记录。
  不过,TDataSet提供了若干个方法可以直接修改整条记录而不是单独的字段,这些方法包括:
.AppendRecord类似于Append,但可以给字段赋值,不需要调用Post;
.InsertRecord类似于Insert,但可以给字段赋值,不需要调用Post;
.SetFields对当前记录的字段赋值,需要显式地调用Post。
  上述三个方法都要传递一个TVarRec类型的数组作为参数,该数组的每一个元素对应着一个字段的值。如果数组的元素个数小于数据集的字段个数,剩下字段的值就是NULL。
  对于没有建立索引的数据集来说,AppendRecord把一条新的记录加到数据集的末尾。对于已建立索引的数据集来说,新记录将自动移到一个恰当的位置。
  SetFields用于对当前记录的字段赋值。在调用SetFields之前,首先要调用Edit,使数据集进入dsEdit状态。调用了SetFields后,需要显式地调用Post函数。
  调用SetFields时,如果您只想对部分字段赋值,让其他字段的值保持不变,可以用NULL或NIL去赋值。
  假设一个数据集中有五个字段,分别是Name、Capital、Continent、Area和Population,可以这样对它们赋值:
CountryTable.InsertRecord([Japan, Tokyo, Asia]);
  上述程序在数据集中插入了一条新的记录,并且对前三个字段赋了值。现在可以再次对当前记录赋值,不过,这次只想对Area字段和Population字段赋值,程序就要这样写:
With CountryTable Do
Begin
If Locate(Name, Japan, loCaseInsensitive) then
Begin
Edit;
SetFields(NIL, NIL, NIL, 344567, 164700000);
Post;
End;
End;
  注意:此处要用NIL而不是NULL,否则,前三个字段会被设为空。
6.8 事 件
  TDataSet的事件主要分为两大类,一类是Before系列,另一类是After系列,列表如下:
.BeforeOpen,AfterOpen发生在数据集打开前后;
.BeforeClose,AfterClose发生在数据集关闭前后;
.BeforeInsert,AfterInsert发生在插入了一条新的记录前后;
.BeforeEdit,AfterEdit 发生在进入dsEdit状态前后;
.BeforePost,AfterPost 发生在写数据集的前后;
.BeforeCancel,AfterCancel发生在取消修改的前后;
.BeforeDelete,AfterDelete发生在删除记录的前后。
  此外,当数据集中增加了一条新的记录时就会触发OnNewRecord事件,当“计算字段”的值需要重算时将触发OnCalcFields事件。
  Before系列的事件常常用来中止操作。例如,当调用Delete函数试图删除当前记录时,在当前记录将要删除前会触发BeforeDelete事件,可以在处理BeforeDelete事件的句柄中调用Abort或触发一个异常放弃删除当前记录,程序示例如下:
Pocedure TForm1.TableBeforeDelete (Dataset: TDataset)
Begin
If MessageDlg(Delete This Record?, mtConfirmation, mbYesNoCancel, 0) <> mrYes Then Abort;
End;
  After系列的事件往往用来在状态栏上通知用户,程序示例如下:
Procedure TForm1.Table1AfterDelete(DataSet: TDataSet);
Begin
StatusBar1.SimpleText := Format(有%d 条记录,[DataSet.RecordCount]);
End;
  OnCalcFields事件主要用于给出“计算字段”的值。AutoCalcFields属性的值决定了什么时候会发生OnCalcFields事件。
  如果AutoCalcFields属性设为True,下列情况下会发生OnCalcFields事件:
.数据集被打开时;
.在数据控件中,输入焦点从一条记录移到另一条记录;
.在数据控件中,输入焦点从一个字段移到另一个字段;
.当前记录被修改或从数据库中检索了一条记录。
  不过,即使AutoCalcFields属性设为False,当数据集中的任意一个非计算字段的值发生变化时都会触发OnCalcFields事件。
  由于OnCalcFields事件有可能是频繁发生的,因此,处理OnCalcFields 事件的代码要尽可能地简短。在AutoCalcFields属性设为True的情况下,在处理OnCalcFields事件的句柄中不能修改数据集的数据,因为一旦当前记录被修改,又要触发OnCalcFields事件,从而导致无限循环。例如,假设您在处理OnCalcFields事件的句柄中调用了Post,就会触发OnCalcFields事件,导致再次调用Post,再次触发OnCalcFields事件……
6.9 TBDEDataSet
  TBDEDataSet是从TDataSet继承下来的,它提供了通过BDE(BorlandDatabase Engine)访问数据的能力。这一节主要介绍TBDEDataSet,读者应当对前面介绍的TDataSet已经有了比较深刻的认识。
  与TDataSet一样,TBDEDataSet也是虚拟的和抽象的,除非您想建立自定义的数据集,否则,一般不需要直接用到TBDEDataSet。
  TBDEDataSet重载了TDataSet中涉及记录导航、索引和书签的方法,增加了一些处理BLOB字段、缓存更新的属性、方法和事件。
6.9.1 CacheBlobs属性
  TBDEDataSet的CacheBlobs属性用于控制BDE是否把BLOB字段的内容放到缓存中。如果这个属性设为True,当应用程序读取BLOB字段的值时,BDE将把BLOB字段的内容放在缓存中,这样,当应用程序下次要读取这个字段的值时,就不必再从数据库服务器那儿去检索,只要直接从内存中取过来就行了,这样可以提高应用程序的性能。
  不过,如果应用程序需要频繁地更新BLOB字段的值,这时候反而应当把CacheBlobs属性设为False,这样能保证检索到的BLOB字段的值总是最新的。
6.9.2 缓存更新
  TBDEDataSet提供了缓存更新的技术。所谓缓存更新就是,应用程序从数据库中检索数据,在本地缓存中建立一个副本,用户对数据进行修改后,也只是反映在缓存中,以后可以调用ApplyUpdates一次性地把所有的修改反映到数据集中。
  可以看出,缓存更新技术可以明显地提高应用程序的性能,而且可以方便地取消修改,只要还没有调用ApplyUpdates。下面列出了TBDEDataSet中有关缓存更新的属性、方法和事件:
.CachedUpdates如果这个属性设为True,缓存更新有效;
.UpdateObject用于指定一个TUpdateSQL构件来更新基于查询的数据集;
.UpdatePending如果缓存中有未决的记录,这个属性就返回True;
.UpdateRecordTypes指定数据集中哪些记录是可见的;
.UpdateStatus返回当前的更新状态;
.OnUpdateError如果更新过程中出错将触发这个事件;
.OnUpdateRecord每更新一条记录就会触发一次这个事件;
.ApplyUpdates把缓存中的数据写到数据集中;
.CancelUpdates把缓存中未决的修改取消;
.CommitUpdates把缓存清掉;l FetchAll从数据库检索所有记录到缓存中;
.RevertRecord撤消对当前记录的修改。
6.10 TDBDataSet
  TDBDataSet是从TBDEDataSet继承下来的,它提供了数据库和会话期管理的能力。
  TDBDataSet中增加了若干个属性和方法用于管理数据库和BDE会话期,包括:
.CheckOpen检查数据库是否已打开;
.Database返回一个TDatabase构件;
.DBHandle返回一个BDE句柄,调用BDE的API时要用到这个句柄;
.DBLocale返回当前的国际语言驱动程序;
.DBSession返回一个BDE会话期对象;
.DatabaseName用于指定要访问的数据库;
.SessionName用于指定一个BDE会话期对象。
  这里详细解释一下DatabaseName属性和SessionName属性。如果应用程序要访问远程数据库服务器如Sybase、Oracle或InterBase,应当用TDatabase构件来连接数据库,此时,应当设置DatabaseName属性指定要连接的数据库,可以设为TDatabase构件的名称。如果没有显式地使用TDatabase构件,DatabaseName属性应当设为BDE 别名。对于Paradox和dBASE表来说,可以设为表的路径。
  SessionName属性用于指定一个BDE会话期对象。如果应用程序没有显式地使用TSession构件,不必设置这个属性。如果应用程序显式地使用了多个TSession构件,应当设置SessionName属性指定其中一个。
  一般来说,应用程序用不到DBHandle、DBLocale和DBSession等属性,除非要直接调用BDE的API。这三个属性都是只读的。
  TDBDataSet中还有一个只读的Provider属性,它能够返回一个IProvider接口。在多层的Client/Server应用程序中,客户程序需要通过IProvider接口与应用服务器通讯。

 

 

 

 
 

 

6.7.2 插入新的记录
  要在数据集中插入新的记录,首先要进入dsInsert状态。要进入dsInsert状态,可以调用Insert或Append函数。不过,调用Insert或Append不一定会使数据集进入dsInsert状态,还取决于CanModify属性的值。
  一旦进入了dsInsert状态,用户就可以在数据控件(一般是TDBGrid)中插入一条新的记录,并给这条记录输入数据。
  如果要通过编程来插入新的记录,就要注意Insert和Append的区别。Insert将把一条新的记录插入到当前记录的前面,而Append将把一条新的记录添加到数据集的末尾。
  插入了新的记录后,应当调用Post或在CachedUpdates属性设为True的情况下调用ApplyUpdates把新的记录写到数据集中。
  如果数据集是已建立了索引的Paradox或dBASE表,新记录将自动移到恰当的位置。
  如果数据集没有建立索引,新记录就插入到数据集的当前位置(Insert)或末尾(Append)。
6.7.3 删除记录
  调用Delete函数将删除当前记录,并且使数据集回到dsBrowse状态。如果窗体上有TDBNavigator构件的话,用户可以单击导航器上的“Delete”按钮删除当前记录。当前记录被删除后,下一条记录就成为当前记录。
  如果删除的本来就是最后一条记录,则前一条记录成为当前记录。
6.7.4 修改整条记录
  除了TDBGrid和TDBNavigator外,大部分数据控件只能工作于数据集的一个或几个字段,而不是整条记录。
  不过,TDataSet提供了若干个方法可以直接修改整条记录而不是单独的字段,这些方法包括:
.AppendRecord类似于Append,但可以给字段赋值,不需要调用Post;
.InsertRecord类似于Insert,但可以给字段赋值,不需要调用Post;
.SetFields对当前记录的字段赋值,需要显式地调用Post。
  上述三个方法都要传递一个TVarRec类型的数组作为参数,该数组的每一个元素对应着一个字段的值。如果数组的元素个数小于数据集的字段个数,剩下字段的值就是NULL。
  对于没有建立索引的数据集来说,AppendRecord把一条新的记录加到数据集的末尾。对于已建立索引的数据集来说,新记录将自动移到一个恰当的位置。
  SetFields用于对当前记录的字段赋值。在调用SetFields之前,首先要调用Edit,使数据集进入dsEdit状态。调用了SetFields后,需要显式地调用Post函数。
  调用SetFields时,如果您只想对部分字段赋值,让其他字段的值保持不变,可以用NULL或NIL去赋值。
  假设一个数据集中有五个字段,分别是Name、Capital、Continent、Area和Population,可以这样对它们赋值:
CountryTable.InsertRecord([Japan, Tokyo, Asia]);
  上述程序在数据集中插入了一条新的记录,并且对前三个字段赋了值。现在可以再次对当前记录赋值,不过,这次只想对Area字段和Population字段赋值,程序就要这样写:
With CountryTable Do
Begin
If Locate(Name, Japan, loCaseInsensitive) then
Begin
Edit;
SetFields(NIL, NIL, NIL, 344567, 164700000);
Post;
End;
End;
  注意:此处要用NIL而不是NULL,否则,前三个字段会被设为空。
6.8 事 件
  TDataSet的事件主要分为两大类,一类是Before系列,另一类是After系列,列表如下:
.BeforeOpen,AfterOpen发生在数据集打开前后;
.BeforeClose,AfterClose发生在数据集关闭前后;
.BeforeInsert,AfterInsert发生在插入了一条新的记录前后;
.BeforeEdit,AfterEdit 发生在进入dsEdit状态前后;
.BeforePost,AfterPost 发生在写数据集的前后;
.BeforeCancel,AfterCancel发生在取消修改的前后;
.BeforeDelete,AfterDelete发生在删除记录的前后。
  此外,当数据集中增加了一条新的记录时就会触发OnNewRecord事件,当“计算字段”的值需要重算时将触发OnCalcFields事件。
  Before系列的事件常常用来中止操作。例如,当调用Delete函数试图删除当前记录时,在当前记录将要删除前会触发BeforeDelete事件,可以在处理BeforeDelete事件的句柄中调用Abort或触发一个异常放弃删除当前记录,程序示例如下:
Pocedure TForm1.TableBeforeDelete (Dataset: TDataset)
Begin
If MessageDlg(Delete This Record?, mtConfirmation, mbYesNoCancel, 0) <> mrYes Then Abort;
End;
  After系列的事件往往用来在状态栏上通知用户,程序示例如下:
Procedure TForm1.Table1AfterDelete(DataSet: TDataSet);
Begin
StatusBar1.SimpleText := Format(有%d 条记录,[DataSet.RecordCount]);
End;
  OnCalcFields事件主要用于给出“计算字段”的值。AutoCalcFields属性的值决定了什么时候会发生OnCalcFields事件。
  如果AutoCalcFields属性设为True,下列情况下会发生OnCalcFields事件:
.数据集被打开时;
.在数据控件中,输入焦点从一条记录移到另一条记录;
.在数据控件中,输入焦点从一个字段移到另一个字段;
.当前记录被修改或从数据库中检索了一条记录。
  不过,即使AutoCalcFields属性设为False,当数据集中的任意一个非计算字段的值发生变化时都会触发OnCalcFields事件。
  由于OnCalcFields事件有可能是频繁发生的,因此,处理OnCalcFields 事件的代码要尽可能地简短。在AutoCalcFields属性设为True的情况下,在处理OnCalcFields事件的句柄中不能修改数据集的数据,因为一旦当前记录被修改,又要触发OnCalcFields事件,从而导致无限循环。例如,假设您在处理OnCalcFields事件的句柄中调用了Post,就会触发OnCalcFields事件,导致再次调用Post,再次触发OnCalcFields事件……
6.9 TBDEDataSet
  TBDEDataSet是从TDataSet继承下来的,它提供了通过BDE(BorlandDatabase Engine)访问数据的能力。这一节主要介绍TBDEDataSet,读者应当对前面介绍的TDataSet已经有了比较深刻的认识。
  与TDataSet一样,TBDEDataSet也是虚拟的和抽象的,除非您想建立自定义的数据集,否则,一般不需要直接用到TBDEDataSet。
  TBDEDataSet重载了TDataSet中涉及记录导航、索引和书签的方法,增加了一些处理BLOB字段、缓存更新的属性、方法和事件。
6.9.1 CacheBlobs属性
  TBDEDataSet的CacheBlobs属性用于控制BDE是否把BLOB字段的内容放到缓存中。如果这个属性设为True,当应用程序读取BLOB字段的值时,BDE将把BLOB字段的内容放在缓存中,这样,当应用程序下次要读取这个字段的值时,就不必再从数据库服务器那儿去检索,只要直接从内存中取过来就行了,这样可以提高应用程序的性能。
  不过,如果应用程序需要频繁地更新BLOB字段的值,这时候反而应当把CacheBlobs属性设为False,这样能保证检索到的BLOB字段的值总是最新的。
6.9.2 缓存更新
  TBDEDataSet提供了缓存更新的技术。所谓缓存更新就是,应用程序从数据库中检索数据,在本地缓存中建立一个副本,用户对数据进行修改后,也只是反映在缓存中,以后可以调用ApplyUpdates一次性地把所有的修改反映到数据集中。
  可以看出,缓存更新技术可以明显地提高应用程序的性能,而且可以方便地取消修改,只要还没有调用ApplyUpdates。下面列出了TBDEDataSet中有关缓存更新的属性、方法和事件:
.CachedUpdates如果这个属性设为True,缓存更新有效;
.UpdateObject用于指定一个TUpdateSQL构件来更新基于查询的数据集;
.UpdatePending如果缓存中有未决的记录,这个属性就返回True;
.UpdateRecordTypes指定数据集中哪些记录是可见的;
.UpdateStatus返回当前的更新状态;
.OnUpdateError如果更新过程中出错将触发这个事件;
.OnUpdateRecord每更新一条记录就会触发一次这个事件;
.ApplyUpdates把缓存中的数据写到数据集中;
.CancelUpdates把缓存中未决的修改取消;
.CommitUpdates把缓存清掉;l FetchAll从数据库检索所有记录到缓存中;
.RevertRecord撤消对当前记录的修改。
6.10 TDBDataSet
  TDBDataSet是从TBDEDataSet继承下来的,它提供了数据库和会话期管理的能力。
  TDBDataSet中增加了若干个属性和方法用于管理数据库和BDE会话期,包括:
.CheckOpen检查数据库是否已打开;
.Database返回一个TDatabase构件;
.DBHandle返回一个BDE句柄,调用BDE的API时要用到这个句柄;
.DBLocale返回当前的国际语言驱动程序;
.DBSession返回一个BDE会话期对象;
.DatabaseName用于指定要访问的数据库;
.SessionName用于指定一个BDE会话期对象。
  这里详细解释一下DatabaseName属性和SessionName属性。如果应用程序要访问远程数据库服务器如Sybase、Oracle或InterBase,应当用TDatabase构件来连接数据库,此时,应当设置DatabaseName属性指定要连接的数据库,可以设为TDatabase构件的名称。如果没有显式地使用TDatabase构件,DatabaseName属性应当设为BDE 别名。对于Paradox和dBASE表来说,可以设为表的路径。
  SessionName属性用于指定一个BDE会话期对象。如果应用程序没有显式地使用TSession构件,不必设置这个属性。如果应用程序显式地使用了多个TSession构件,应当设置SessionName属性指定其中一个。
  一般来说,应用程序用不到DBHandle、DBLocale和DBSession等属性,除非要直接调用BDE的API。这三个属性都是只读的。
  TDBDataSet中还有一个只读的Provider属性,它能够返回一个IProvider接口。在多层的Client/Server应用程序中,客户程序需要通过IProvider接口与应用服务器通讯。

 

 

 


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
【 MATLAB 】信号处理工具箱之 fft 案例分析发布时间:2022-07-18
下一篇:
使用matlab生成动态链接库.DLL文件发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap