pb 数据窗口更新mysql_PB-数据窗口缓冲区与数据修改状态

本文介绍了PB数据窗口在处理数据时的四个缓冲区:主缓冲区、删除缓冲区、过滤缓冲区和原始缓冲区,详细阐述了它们各自的作用和数据状态管理。通过缓冲区,数据窗口能正确处理用户的删除、插入和修改操作。同时,讨论了如何利用数据窗口函数进行数据恢复、撤销操作和协调多个数据窗口的更新。
摘要由CSDN通过智能技术生成

1--缓冲区的介绍

在应用程序运行时,用户对数据窗口进行的操作情况是很复杂的,删除、插入、修改等操作有可能都会发生。记录哪些数据修改过、哪些数据需要删除、哪些数据是新增加的等等,都是很重要的工作,以便数据保存时能够正确修改数据库。这些工作都是由数据窗口缓冲区来完成的。

数据窗口在运行时要创建四个缓冲区,分别是主缓冲区、删除缓冲区、过滤缓冲区和原始缓冲区,这四个缓冲区各司其职、共同配合,来保证数据窗口对数据的正确处理。下面分别加以介绍。

1.主缓冲区[Primary Buffer]--存放检索出来的数据,但不包括过滤掉和删除掉的数据。

最重要的一个缓冲区,保存的是当前显示在数据窗口中的所有数据以及它们的修改状态,函数中的缓冲区参数缺省也是该缓冲区,这个缓冲区是存放填充窗口中DataWindow控件中数据的,调用DataWindow的Retrieve()函数和InsertRow()函数可以将数据填入这个缓冲区中。当使用有关DataWindow删除和过滤函数时,相应记录将从这一缓冲区中删除。而在执行DataWindow的Update()函数时,PowerBuilder将查看这一缓冲区中的记录,以形成SQL INSERT和UPDATE语句。

2.删除缓冲区[Delete Buffer]--存放从主缓冲区中删除掉的数据。

该缓冲区保存的是用DeleteRow()或者dw_1.rowsmove(1,3,primary!,dw_1,1,delete!)函数从Primary Buffer中删除的记录,执行Update()函数时,系统根据这一缓冲区的记录形成DELETE语句。在数据没有提交到数据库之前,可以从该缓冲区中将数据恢复出来,数据提交后,该缓冲区中的数据清空。

3.过滤缓冲区[Filter Buffer]--存放从主缓冲区中过滤掉的数据。

该缓冲区中保存的是没有通过【过滤条件】的所有数据,这些数据在存储时同主缓冲区的数据一起生成相应的insert或update语句。存储的是从Original Buffer使用Filter()函数过滤到Primary Buffer中后剩余的记录。

4.原始缓冲区[Original Buffer]--存放从数据库里检索到的原始数据。

这一缓冲区存储的是DataWindow最初执行retrieve()函数时得到的全部记录。当提交数据库时,根据Primary Buffer生成的UPDATE语句和根据Delete Buffer生成的DELETE语句都要依据这一缓冲区来构造这些SQL语句中的Where子句。它由PowerBuilder内部维护,PB所提供的任何函数都无法改变它的值,不过通过PowerBuilder所提供的GetItemX系列的函数可以读出DataWindow最初从数据库中查到的原始值。通过这些函数我们可以编程实现所谓的“Undo”功能,并且得到在使用乐观锁时形成提交数据库的WHERE子句。如下:

String LName,LName1

LName = dw_2.GetItemString(1, "name", Primary!, TRUE)原始缓冲区数据

LName1 = dw_2.GetItemString(1, "name", Primary!, false)修改后的主缓冲区数据

或用点状表示法

LName=string(dw_top.object.name.ORIGINAL[1])原始缓冲区数据

修改后的主缓冲区数据

LName1=string(dw_top.object.name.Primary[1])或string(dw_top.object.name.CURRENT[1])

综上所述,不管我们对缓冲区数据做任何处理,只要没有执行UPDATE()时,就不会对后台数据库有影响。

2--数据缓冲区的状态值

1,所有这些数据的移送无需脚本的干预,只管使用相应的函数即可。

日常使用中很多数据窗口函数经常对这四个缓冲区进行操作【original缓冲区在脚本中很少使用】,默认缺省的缓冲区为Primary!。这三个[original除外]缓冲区,除了保存相应的数据外,都自动维护这些数据的修改标志,它们之间的协作也是自动维护的。例如,当使用过滤函数时,没有通过过滤条件的数据自动从Primary缓存区移送到Filter缓存区;执行删除操作时,数据自动从Primary缓存区移送到Delete缓存区。

2,一些特殊情况下需要人工干预,特别是在需要数据恢复时。

经常使用的方法是,专门建立一个数据窗口用来显示缓冲区的数据,使用函数RowMove,它可以将数据从一个缓冲区移动到另外缓冲区中,在两个数据窗口之间移动数据。该函数的语法是:

dwcontrol.RowsMove ( startrow, endrow, movebuffer, targetdw, beforerow,targetbuffer )

其中,dwcontrol是进行移动操作的源数据窗口;startrow和endrow是要移动数据的范围(包括这两个行号的数据);movebuffer指要从哪个缓存区移出数据,可以是Primary!、Delete!、Filter;targetdw是目标数据窗口控件名称;beforerow表示在目标数据窗口的哪一行之前插入移入的数据,如果该数值比目标数据窗口的行数大,则在最后插入移入的数据;targetbuffer是目标缓存区,取值同movebuffer一样。

如dw_1.rowsmove(1,3,primary!,dw_1,1,delete!)//将要删除的行移动到删除缓冲区然后再UPDATE

dw_cur.RowsMove(dw_cur.GetRow(),dw_cur.GetRow(),Primary!,dw_del,dw_del.RowCount() + 1,Primary!)

3,另外一种情况是直接修改缓冲区数据修改标识

行与列的修改状态在PowerBuilder中为dwItemStatus枚举类型值,使用函数dwcontrol.GetItemStatus ( row, column, Primary! )可以获取该缓冲区内指定单元的状态,当参数column为0时,表示读取整个列的修改状态。有以下状态。

NotModified!:指定行或列处的数据和原始数据相同,没有修改过。

DataModified!:指定行或列处的数据和原始数据不同,修改过。

New!:该数据行是新增加的,但还没有在该行上输入数据,只适用于行,不适用于单个列。

NewModified!:该数据行是新增加的,并且已经在该行上录入了数据,改变是通过用户键盘输入或SetItem()函数,也可能是由于它的某列具有缺省值,本状态只适用于行,不适用于单个列。

数据窗口中行或列的修改状态决定Update()函数将为该行或该列产生何种类型的SQL语句。对主缓冲区和过滤缓冲区中的行,Update为状态是NewModified!的行产生Insert语句,为状态是DateModified!的行产生Update语句,只有状态是DataModified!的列才会包含在Update语句中。对删除缓冲区中的行,若其状态是New!或NewModified!,则Update语句不会为其产生Update语句。

这些修改标识都是由数据窗口自动维护的,一般情况下没有必要编写脚本修改这些标记,但并不是说就不能修改。PowerBuilder提供了函数SetItemStatus,它的语法是:

dwcontrol.SetItemStatus ( row, column, dwbuffer, status )

其中,row参数指定将要修改状态的行;column参数指定将要修改状态的列(可以是整型的列号,也可以是string类型的列名),当列号为0时表示要修改row指定的整行的状态;dwbuffer指定要修改哪个缓冲区(肯定不能是original),status为上面的四个取值中的一个,但不是任意的取值,因为有些状态不能用该函数设置成另外一种状态,必须是能够转换的状态。对于如何改变状态,PowerBuilder有一些限制,表1给出了这种限制,其中Yes表示可把初始状态改变为指定状态,No则表示不可以。

表1数据修改状态设置约束

初始状态指定状态New!NewModified!DataModified!NotModified!New!——YesYesNoNewModified!No——YesNew!DataModified!NewModified!Yes——YesNotModified!YesYesYes——

表中的Yes表示可以使用SetItemStatus进行该状态设置,No表示不会产生预期的状态,如果标明了某个特定的状态,则说明是新的状态,而不是期望的状态。例如,数据窗口dw_1的第1行第1列的当前状态为DataModified!,使用函数dw_1.SetItemStatus(1,1,New!)后,第1行第1列的状态改变为NewModified!。同样对于该数据窗口dw_1,如果使用函数dw_1.SetItemStatus(1,1,NotModified!),则会将其状态改变为NotModified!。当从一种状态不允许转变到另一种状态时,可以修改成其他一个中间状态,然后再进行一次转换。例如,要从new!改成NotModified,应该首先转换到DataModified!。

利用函数RowsCopy、RowsMove可以在不同DataWindow控件(或DataStore对象)之间或同一DataWindow控件(或DataStore对象)的不同缓冲区之间复制、移动数据行。

当某行在删除缓冲区中时,或者在主缓冲区或过滤缓冲区中,并且状态为NewModified!或DataModified!时,其更新标志被设置。函数dw_control.ResetUpdate()清除DataWindow或DataStore中主缓冲区和过滤缓冲区中的更新标志并清空其删除缓冲区。清除更新标志后,所有行的状态为NotModified!或New!。

3--应用举例

(1)在数据窗口中,某些列常具有缺省值,或我们在执行了InsertRow操作后立即使用SetItem函数为某些列赋值。如果用户执行了一个插入操作后立即关闭窗口会触发closequery事件,这时会提示用户记录已经被修改,但用户并没有感觉到对数据的修改。为避免出现这种情况,可作如下处理:

intli_new_row

li_new_row=dw_l.InsertRow(0)

//通过SetItem函数为列赋值

dw_l.SetItem(……)

//将新行的修改状态置为NotModified!

dw_l.SetItemStatus(li_new_row,0,primary!,NotModified!)

(2)在应用程序中提供Undo功能,将实现很好的用户友好效果。本例中将数据窗口dw_l中的当前行、当前列的显示值置为从数据库中检索出的原始值:

string ls_ori_val

ls_ori_val=dw_l.GetItemString(dw_l.GetRow(),dw_l.GetColumn(),Primary!,True)

dw_l.SetText(ls_ori_val)

(3)在协调两个DataWindow对象dw_l、dw_2的更新时,若其中一个更新失败,应阻止重设更新标志,以便回滚事务,一旦所有数据窗口都已成功更新,就可使用COMMIT结束该事务,并使用ReSetUpdate重新设置数据窗口的状态标志。

Int li_ret_code

li_ret_code=dw_l.Update(True,False)//阻止重设更新标志

If li_ret_code=l then

li_ret_code=dw_2.Update(True,False)//阻止重设更新标志

lf li_ret_code=l then

dw_l.ResetUpdate()//清除更新标志

dw_2.ResetUpdate()//清除更新标志

COMMIT;

Else

ROLLBACK;

Endif

Endif

(4)将数据行从删除缓冲区移到主缓冲区,实现取消删除的功能。

dw_l.RowsMove(l,dw_l.DeletedCount(),Delete!,dw_l,l,Primary!)

数据存在主次表时,当更新了次表数据后,主表数据在后台有更变时。可利用刷新主表当前行的方法重显主表数据。 /************************************************************ 函数名称: f_refresh_currentrow(adw) 功 能: 刷新DW当前行数据,不可刷新NO update or 带arguments的DW 参数说明: adw 目标DW 返 回 值: integer 成功返回1,失败返回-1 作 者: sean 创建时间: 2010年8月18日 ************************************************************/ string ls_dataobject string ls_keys[] //key Column Name string ls_dbname[] //key field Name string ls_coltype[] //field style string ls_tablenm //table name string ls_condition //sql Condition long ll_currentrow //Current Row numeric long ll_column //Column count integer i datawindow ldw datastore ldatastore ldw=adw if ldw.rowcount( )=0 then return -1 elseif trim(ldw.describe( "datawindow.table.arguments"))<>'?' then messagebox('','刷新数据窗口当前行失败!,数据窗口需要参数',exclamation!) return -1 else ll_currentrow=ldw.getrow( ) FOR ll_column = 1 TO long(ldw.object.datawindow.column.count)//key names If ldw.Describe("#"+string(ll_column)+".key") ='yes' Then i++ ls_keys[i]=ldw.Describe("#"+string(ll_column)+".name") ls_dbname[i]=ldw.Describe("#"+string(ll_column)+".dbname") ls_coltype[i]=ldw.Describe("#"+string(ll_column)+".coltype") End If NEXT if upperbound(ls_keys[])=0 then messagebox('','刷新数据窗口当前行失败!,没有主键',exclamation!) return -1 else ls_tablenm=left(ls_dbname[1],pos(ls_dbname[1],'.') -1) //table name for i=1 to upperbound(ls_keys[]) if pos('numb,deci,long,',LeftA(ls_coltype[i],4) +',')>0 then ls_condition+="and "+ls_dbname[i]+"="+string(f_getitem(ldw,ll_currentrow,ls_keys[i])) else ls_condition+="and "+ls_dbname[i]+"='"+string(f_getitem(ldw,ll_currentrow,ls_keys[i]))+"'" end if next ls_condition=mid(ls_condition,4) //sql Condition ldatastore=create datastore ldatastore.dataobject=ldw.dataobject ldatastore.settransobject( sqlca) if f_addwhere_retrieve(ldatastore,ls_condition)=1 then if ldatastore.rowcount( )=1 then ldw.object.data[ll_currentrow]=ldatastore.object.data[1] ldw.setitemstatus( ll_currentrow, 0, primary!, NotModified!) //if ldw.getrow( )<>ll_currentrow then ldw.scrolltorow( ll_currentrow) end if else messagebox('','刷新数据窗口当前行失败!,条件语法错误',exclamation!) return -1 end if destroy ldatastore end if end if
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值