分页加载与流水账

本节的内容,可以参考CaseStudy目录下的文件:分页流水账.Table

关于流水账的设计,请参考:高效率的流水账

由于分页加载往往意味着大数据量、网络环境、多用户等元素,所以上述的流水账设计方案将不再适用,需要重新 设计。

好消息是分页加载同时也意味着每次加载的数据量有限,我们可以充分利用这个优势,在每次加载数据后重算余额,其实这样的设计更加符合实际应用的需求。

示例一

同样假定有个简单的流水帐式的表格,希望在分页加载的情况下,输入收入和支出,能够自动计算出余额:

设计步骤:

1、删除原来的余额列,然后在项目事件Initialize中设置代码:

DataTables("例子一").DataCols.Add("余额",Gettype(Double))  '添加余额列,用于动态显示余额

技巧:

A、由于余额是每次加载数据后动态计算得出的,所以这里应该采用表达式列,而不是数据列;这样不仅可以节省存储空间,更重要的是,不会因为重算余额导致系统误认为此行被修改了,需要保存。
B、当然这个表达式列和我们平时的表达式列不同,因为没有给它设置表达式;没有设置表达式的表达式列,可以用代码向该列赋值,希望大家能记住这一点。
C、也许有人会问,为什么要在Initialize事件,而不是AfterOpenProject事件添加列?这是因为在Initialize事件添加的列,可以保存列宽和列位置。

2、将DataColChanged事件设为:

Select Case e.DataCol.Name
    Case
"
收入","支出"
        Dim dr As DataRow
        Dim drs As List(of DataRow)
        dr = e.DataTable.Find("[_SortKey] < " & e.DataRow("_SortKey"), "[_SortKey] Desc")
'
找出上一行
        If dr Is Nothing Then
'
如果没有找到上一行,说明本行就是第一行
           
'
计算之前的结存
            Dim jk As Double
            Dim ck As Double
            jkDataTables(
"
例子一").SQLCompute("Sum(收入)","[_SortKey] < " & e.DataRow("_SortKey"))
            ck DataTables(
"
例子一").SQLCompute("Sum(支出)","[_SortKey] < " & e.DataRow("_SortKey"))
            e.DataRow(
"
余额") = e.DataRow("收入") - e.DataRow("支出") + jk -ck
            dr = e.DataRow
        End If
        drs = e.DataTable.Select("[_SortKey] >= " & dr("_SortKey"), "[_SortKey]")
        For i As Integer = 1 To drs.Count - 1
'
重算余下行的余额
            drs(i)(
"
余额") = drs(i-1)("余额") + drs(i)("收入") - drs(i)("支出")
       
Next
End
Select

上述代码的原理:

A、如果修改的是第一行,那么就先用
SQLCompute方法,从后台计算出此行之前的结存,第一行的收入减去支出,再加上之前的结存,就是第一行的余额。
B、如果不是第一行数据,那么该行的收入减去支出,再加上上一行的结存,就是此行的余额。

可以看出,由于有了SQLCompute等后台数据处理行数,设计这么一个分页加载的流水账,变得轻松起来了。

3、表事件AfterMoveRow的代码保持不变:

Dim Key As Decimal
Dim
Index As Integer
Dim
dc As DataCol
Index = Math.Min(e.OldIndex, e.NewIndex)
Key = e.
Table.Rows(Index)("_SortKey")
dc = e.
Table.DataTable.DataCols("入库")
dc.RaiseDataColChanged(
"[_SortKey] >= "
& Key)

4、表事件DataRowDeleting的代码同样保持不变:

e.DataRow("收入") = 0
e.
DataRow("支出") = 0

5、设置表事件AfterLoad的代码为:

If e.DataTable.DataRows.count > 0 Then
   Dim dr As DataRow = DataTables("例子一").Find("","[_SortKey]")
   e.DataTable.DataCols(
"
支出").RaiseDataColChanged(dr)
End
If

这段代码在每次加载数据后执行,模拟拟第一行的支出发生变化, 刷新已加载行的余额,这是非常关键的一步。

6、最后AfterOpenproject事件代码设置为:

With DataTables("例子一")
    .LoadOver = "_SortKey" '设置分页加载依据列
    .LoadFilter = "" '清除加载条件

End
With
Forms
("窗口1").Open() '打开设计好的分页加载窗口

提示: 由于我们的流水账是根据_SortKey的顺序计算的,所以分页加载的语句列必须设置为_SortKey列。

示例二

对于下面这中区分产品的分页加载流水账(参考示例文件中的例子二):

只需将DataColChanged事件代码改为:

Select Case e.DataCol.Name
    Case "产品","入库","出库"
        Dim dr As DataRow
        Dim mr As DataRow = e.DataRow
        Dim drs As List(of DataRow)
       
Dim jk As Integer
        Dim ck As Integer
        dr = e.DataTable.Find("[_SortKey] < " & mr("_SortKey") &
" And [
产品] = '" & mr("产品") & "'", "[_SortKey] Desc")
        If dr Is Nothing Then
'
如果是第一行,计算结存
            jk DataTables(
"
例子二").SQLCompute("Sum(入库)","[_SortKey] < " & mr("_SortKey") & " And 产品 = '" & mr("产品") & "'")
            ck DataTables(
"
例子二").SQLCompute("Sum(出库)","[_SortKey] < " & mr("_SortKey") & " And 产品 = '" & mr("产品") & "'")
            mr(
"
库存") = e.DataRow("入库") - e.DataRow("出库") + jk - ck
            dr = mr
        End If
        drs = e.DataTable.Select("[_SortKey] >= " & dr("_SortKey") &
" And [
产品] = '" & dr("产品") & "'", "[_SortKey]")
        For i As Integer = 1 To drs.Count - 1
            drs(i)(
"
库存") = drs(i-1)("库存") + drs(i)("入库") - drs(i)("出库")
        Next
        If e.DataCol.Name =
"
产品" AndAlso e.OldValue IsNot Nothing AndAlso e.OldValue <> e.NewValue Then '如果修改的是产品列
            dr = e.DataTable.Find("[_SortKey] < " & mr("_SortKey") &
" And [
产品] = '" & e.OldValue & "'", "[_SortKey] Desc") '找出旧产品的上一行
            If dr Is Nothing Then
'
如果不存在上一行,那么本行就是旧产品的第一行,由于已经被修改为新产品,需要找出旧产品现在的第一行
                dr = e.DataTable.Find(
"[
产品] = '" & e.OldValue & "'", "[_SortKey]") '找出旧产品现在的第一行
                If dr IsNot Nothing Then
'
如果找到,计算库存
                    jkDataTables(
"
例子二").SQLCompute("Sum(入库)","[_SortKey] < " & mr("_SortKey") & " And 产品 = '" & e.OldValue & "'")
                    ckDataTables(
"
例子二").SQLCompute("Sum(出库)","[_SortKey] < " & mr("_SortKey") & " And 产品 = '" & e.OldValue & "'")
                    dr(
"
库存") = dr("入库") - dr("出库") + jk - ck
                End If
            End If
            If dr IsNot Nothing Then
                drs = e.DataTable.Select("[_SortKey] >= " & dr("_SortKey") &
" And [
产品] = '" & dr("产品") & "'", "[_SortKey]")
                For i As Integer = 1 To drs.Count - 1
                   
drs(i)("库存") = drs(i-1)("库存") + drs(i)("入库") - drs(i)("出库")
                Next
            End If
        End
If

End
Select

表事件AfterMoveRow的代码保持不变:

Dim Key As Decimal
Dim
Index As Integer
Dim
Filter As String
Dim
r As Row
Index
= Math.Min(e.OldIndex, e.NewIndex)
Key
= e.Table.Rows(Index)("_SortKey")
r
= e.Table.Rows(e.NewIndex)
Filter
= "[_SortKey] >= " & Key & " And [产品] = '" & r("产品") & "'"
e
.Table.DataTable.DataCols("入库").RaiseDataColChanged(Filter)

表事件DataRowDeleting的代码保持不变:

e.DataRow("入库") = 0
e
.DataRow("出库") = 0

表事件AfterLoad的代码有变化:

Dim drs As New List(of DataRow)
For
Each nm As String In e.DataTable.GetValues("产品") '找出每个产品的第一行数据, 添加到集合drs
    drs.Add(e.DataTable.Find("
产品 = '" & nm & "'", "[_SortKey]"))
Next
For
Each r As DataRow In drs
    e.DataTable.DataCols("
入库").RaiseDataColChanged(r)
Next

这个代码在数据加载后,重置每个产品第一行的入库列,刷新每个产品的库存,重置某产品的第一行,等于该产品所有行的库存都会刷新,所以没有必要重置所有行的。

 

 

 

 

 


本页地址:http://www.foxtable.com/webhelp/scr/2926.htm