DataWindow的数据更新技术及应用

DataWindow的数据更新技术及应用

华铨平

摘要:

本文介绍DataWindow的数据缓冲技术,利用该技术探索一种对非数据源表数据即时更新操作的实现方法。

关键字:数据窗口、数据缓冲、即时更新。

正文:

PowerBuilder是一个强有力的数据库前端开发工具,其DataWindow(数据窗口)控件充分体现了PowerBuilder与数据库系统的紧密结合,是PowerBuilder中拥有专利技术最多、应用最为广泛的控件。它对数据的处理方法相当简洁,有关DataWindow的数据显示、编辑、有效性检验、报表打印技术方面的文章介绍的也很多。本文结合作者多年的开发经验,利用DataWindow的数据缓冲技术,探索一种对非数据源表数据即时更新操作的实现方法。

一、DataWindow的数据缓冲机制

PowerBuilder虚拟机在处理数据窗口时,为每一个DataWindow开辟了主记录缓冲区(Primary)、删除记录缓冲区(Deleted)、过滤记录缓冲区(Filter)。每个缓冲区又分两类,当前缓冲区(Current)存储当前编辑过的数据,原来缓冲区(Original)存储最初收到的数据。数据行有四种状态:NotModified、DataModified、New、NewModified,列有二种状态:NotModified、DataModified。每次对DataWindow调用Update函数时产生对应的SQL语句如下(假定在DataWindow的Update属性窗口中设置关键字修改用Update):

 

Primary

Deleted

Filter

NotModified

不产生

Delete语句

不产生

DataModified

Update语句

Delete语句

Update语句

New

不产生

不产生

不产生

NewModified

Insert语句

不产生

Insert语句

备注

用Current数据

用Original数据

用Current数据

DataWindow从数据库收到数据后,首先存储在主记录缓冲区,删除某个记录就将该记录移到删除记录缓冲区,将过滤的记录存储在过滤缓冲区。数据初始状态为NotModified,数据有更改后状态为DataModified,且原来缓冲区中仍然保留着原来的数据。新增记录状态为New,有数据输入后状态置为NewModified。

二、相关DataWindow函数

ModifiedCount()函数根据Primary缓冲区和Filter缓冲区判别DataWindow中已被修改的行数。DeletedCount()返回Deleted缓冲区中记录的行数,即已经删除记录的行数。这两个函数可以判断数据是否被更改。

要设置某缓冲区记录行或列的状态,可以用函数SetItemStatus ( row, column, dwbuffer, status ),其中:row是要设置状态的记录行号,column是要设置状态的记录列号,为零表示设置行状态。dwbuffer是要设置状态的数据缓冲区类型。status是要设置的状态值。同样通过函数GetItemStatus ( row, column, dwbuffer)可以获取某缓冲区记录行或列的状态。

函数GetNextModified ( row, dwbuffer )的功能是从row行开始查找下一个修

改过的记录行号。

对DataWindow单个数据项的访问,可以用这样的表达式: dwcontrol.Object.columnname{.buffer}{.datasource}[row]

默认访问的是主缓冲区的当前值,例如dw_detail.object.shuliang[2]访问dw_detail对象主缓冲区第2行shuliang列的当前值;dw_detail.object.shuliang.Delete.Original[2]访问删除缓冲区第2行shuliang的原来值。

三、应用实例

在数据库应用系统设计中,经常会碰到这样的问题,比如对客户销售单据编辑修改完成后,希望能及时更改客户库存、客户应收帐款表的本期销售的值。笔者和同事曾采用过对数据库相关表的定时或手动刷新,在数据库系统中也设计过UPDATE、INSERT触发器以达到即时更新客户库存、客户应收帐款的值。这里,笔者用DataWindow数据缓冲机制来解决这一问题。

1、问题涉及的数据库表结构

客户销售单头表,字段有单据号、日期、客户号等,是dw_master控件的主要数据源表。

客户销售单项表,字段有单据号、序号、产品号、售价、数量等,是dw_detail控件的主要数据源表。

客户收付存表,字段有月份号、客户号、产品号、期初库存数量、金额、本期收入数量、金额、本期付出数量、金额等。

客户应收帐款表,字段有月份号、客户号、期初应收、本期开票、本期收款等。

2、窗口对象的设计

销售单据编辑窗口对象主要有主从DataWIndow控件dw_master、dw_detail处理销售单头、项数据,窗口界面如图(一)。

clip_image001

图(一)

其中定义了在保存单据数据时调用的窗口函数wf_updatekucun,主要代码:

lu_update = CREATE u_updatekucun_xs//建立自定义的对象

IF lu_update.of_init_bqfc(dw_master) < 0 THEN RETURN 1//初始化调用

li_ret = lu_update.of_updatesfcdetail_bqfc(dw_detail)//更改客户收付存表

3、设计自定义不可视对象

窗口函数调用了一个PowerBuilder的自定义不可视对象u_updatekucun_xs 来处理库存、应收帐款的即时更新,该对象主要实例变量及函数说明如下:

1)主要实例变量及说明

datawindow dw_detail,dw_master //存放传递来的主从DataWindow控件对象

string ls_kh_cur,ls_kh_org //存放主dw_master中当前、原来客户号

Dec ld_je_cur,ld_je_org//存放从dw_detail中当前、原来销售金额

long ll_sl_cur,ll_sl_org//存放从dw_detail中当前、原来销售数量

string ls_cp_cur,ls_cp_org//存放从dw_detail中当前、原来产品号

Boolean ib_update = TRUE //初始操作后,是否要继续修改库存

 

2)主要函数及说明

函数of_init_bqfc是进行初始操作,传递销售单编辑窗口中的主DataWindow控件对象,获取该对象中当前、原来客户号。

integer of_init_bqfc (ref datawindow adw_master);

ls_yuefen = f_getbenqi_yuefen()//取本期帐册月份号

dw_master = adw_master//该DataWindow控件对象至多有1行记录。

IF dw_master.GetRow() = 0 THEN //记录已删除

IF dw_master.DeletedCount() = 0 THEN //删除行是新行

ib_update = FALSE

Return 1

END IF

//删除行是旧行,则

ls_kh_org = dw_master.object.kehu_id.Delete.Original[1]//取原来的客户号

ls_kh_cur = ls_kh_org//该行无实际意义,此时不会有dw_dettail主缓冲区记录

ELSE //主dw_master有记录,可能是新的,也可能是旧的

dwItemStatus Rowstatus

Rowstatus=dw_master.GetItemStatus(1,0, Primary!)//当前行状态

CHOOSE CASE Rowstatus //根据当前行状态作不同处理

CASE NewModified!, NotModified! //是新行且已更改或是旧行且没有更改

ls_kh_cur= dw_master.object.kehu_id[1]

ls_kh_org= ls_kh_cur

CASE DataModified! //是旧行且已更改

ls_kh_cur= dw_master.object.kehu_id[1]

ls_kh_org= dw_master.object.kehu_id.Original[1]

END CHOOSE

END IF

RETURN 1

函数of_updatesfcdetail_bqfc则根据销售项数据修改客户的相应值。

integer of_updatesfcdetail_bqfc (ref datawindow adw_detail);

dw_detail = adw_detail

IF ib_update = FALSE THEN RETURN 1

//处理主缓冲区记录

long Rows, row = 0, count = 0,i

dwItemStatus Rowstatus,status

Rows = dw_detail.RowCount( )

//如果改变客户,则每行dw_detail未修改的记录都认为已修改

IF ls_kh_cur <> ls_kh_org THEN

FOR i = 1 to dw_detail.RowCount()

Rowstatus=dw_detail.GetItemStatus(i,0, Primary!)

IF Rowstatus = NotModified! THEN

dw_detail.SetItemStatus(i,0, Primary!,DataModified!)

END IF

 

NEXT

END IF

DO WHILE row <= Rows

row = dw_detail.GetNextModified(row, Primary!)//取第一个修改过的记录行号

IF row <= 0 THEN EXIT

Rowstatus=dw_detail.GetItemStatus(row,0, Primary!)//当前行状态

CHOOSE CASE Rowstatus

CASE NewModified! //是新行且已更改,用当前值更改

of_GetRow_cur(row,"Primary") //取Primary缓冲区row行当前值

//当前客户库存的本期付出加上当前值

IF of_update_bqfc(ls_kh_cur,ls_cp_cur,ll_sl_cur,ld_je_cur) < 0 THEN

Return -1

END IF

CASE DataModified! //是旧行且已更改

//原来客户库存的本期付出减去原来值

of_GetRow_org(row,"Primary")

IF of_update_bqfc(ls_kh_org,ls_cp_org,- ll_sl_org, - ld_je_org) < 0 THEN

Return -1

END IF

//当前客户库存的本期付出加上当前值

of_GetRow_cur(row,"Primary")

IF of_update_bqfc(ls_kh_cur,ls_cp_cur,ll_sl_cur,ld_je_cur) < 0 THEN

Return -1

END IF

END CHOOSE

LOOP

//处理Delete缓冲区区记录

Rows = dw_detail.DeletedCount( )

FOR row = 1 to Rows //原来客户库存的本期付出减去原来值

of_GetRow_Org(row,"Delete")

IF of_update_bqfc(ls_kh_org,ls_cp_org, - ll_sl_org, - ld_je_org) < 0 THEN

Return -1

END IF

NEXT

RETURN 1

函数of_getrow_cur获取指定缓冲区数据行的当前值。

integer of_getrow_cur (integer row, string buffer);

Dec ld_shoujia

CHOOSE CASE buffer

CASE "Primary"

ls_cp_cur= dw_detail.object.chanpin_id[row]

ll_sl_cur = dw_detail.object.shuliang[row]

ld_je_cur = ll_sl_cur * dw_detail.object.shoujia[row]

CASE "Delete"

ls_cp_cur = dw_detail.object.chanpin_id.Delete[row]

ll_sl_cur = dw_detail.object.shuliang.Delete[row]

ld_je_cur = ll_sl_cur * dw_detail.object.shoujia .Delete[row]

CASE "Filter"

ls_cp_cur = dw_detail.object.chanpin_id.Filter[row]

ll_sl_cur = dw_detail.object.shuliang.Filter[row]

ld_je_cur = ll_sl_cur * dw_detail.object.shoujia.Filter[row]

END CHOOSE

RETURN 1

函数of_getrow_org获取指定缓冲区指定数据行原来的产品号、数量、金额赋值给实例变量ls_cp_org,ll_sl_org,ld_je_org,代码同函数of_getrow_cur类似,只是访问时在对应列对象后加”. Original”以表明访问的是缓冲区的原来值。如:

ls_cp_org = dw_detail.object.chanpin_id.Original[row]

函数of_update_bqfc的功能是修改客户库存收付存表的本期付出值、应收帐款表的本期销售值。

integer of_update_bqfc (string ls_id, string ls_cp_id, long ll_sl, decimal ld_je);

UPDATE bsc_sfcdetail

SET bqfc = bqfc + :ll_sl , bqfc_j = bqfc_j + :ld_je

WHERE chanpin_id = :ls_cp_id AND id = :ls_id;

IF NOT sqlca.SQLNRows > 0 THEN//是新记录,则

INSERT INTO bsc_sfcdetail (yuefen,id, chanpin_id,bqfc,bqfc_j)

VALUES (:ls_yuefen,:ls_id,:ls_cp_id,:ll_sl, :ld_je) ;

END IF

f_checkTransOk(SQLCA) //自定义函数,检查数据库事务对象执行状况

......

更改应收帐款表cw_sfcdetail本期销售值的方法与更改客户收付存表本期付出值的方法类似。

RETURN 1

四、结束语

在笔者参与开发的分销管理系统中对发货单、入库单、调拨单等数据编辑窗口也采用了DataWindow的数据更新技术即时更新相关数据表,使用户在这些单据的编辑过程中能及时看到最新库存、应收帐款等敏感信息。数据窗口控件是PowerBuilder中最令人激动的控件,深入了解数据窗口的处理机制,灵活运用数据窗口技术,一定会使程序员获益非浅。在笔者开发过程中对每个单据又分为”未处理”、”在处理”、”已处理”,根据不同状态间的变化确定不同的更新策略。在宁波维科销售有限公司、兴洋浙东毛毯有限公司等单位具体应用,取得较好的效果。

posted on 2010-06-30 22:57  枫叶飞舞  阅读(3007)  评论(0编辑  收藏  举报