高效率的流水账设计
本示例可以参考CaseStudy目录下的文件:高效率流水账.Table
上一节介绍的流水账设计方法是比较低效的,下面介绍一种更为高效的设计方法,希望大家仔细体会。
示例一
同样假定有个简单的流水帐式的表格,输入收入和支出,能够自动计算出余额:
我们采用和上一节完全不同的方法,不再通过累计出之前的收入和支出,利用二者相减得出余额,而是通过上一行的余额和本行收入和支出,计算出本行的余额,显然这样的计算方式要高效很多。
为此将DataColChanged事件设为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
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 '如果没有找到上一行,说明本行就是第一行 e.DataRow("余额") = e.DataRow("收入") - e.DataRow("支出") 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 |
上述代码的原理是:
表事件AfterMoveRow的代码保持不变:
Dim
Key As Decimal表事件DataRowDeleting的代码同样保持不变:
e.DataRow("收入")
= 0
e.DataRow("支出")
= 0
如果是多人同时编辑数据,还需要在项目事件AfterOpenproject中加入代码:
Dim
dr As
DataRow
dr =
DataTables("例子一").Find("","[_SortKey]")
If
dr IsNot
Nothing Then
'模拟第一行的支出发生变化,
刷新已加载行的余额.
DataTables("例子一").DataCols("支出").RaiseDataColChanged(dr)
End
If
这样每次打开项目,都会自动重算余额列,确保数据准确,注意我们没有必要重置所有行,只需重置第一行即可
示例二
对于下图所示这种区分产品的流水账:
需要将DataColChanged事件代码改为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
Select Case
e.DataCol.Name Case "产品","入库","出库" Dim dr As DataRow Dim mr As DataRow = e.DataRow Dim drs As List(of DataRow) dr = e.DataTable.Find("[_SortKey] < " & mr("_SortKey") & " And [产品] = '" & mr("产品") & "'", "[_SortKey] Desc") If dr Is Nothing Then mr("库存") = mr("入库") - mr("出库") 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 dr("库存") = dr("入库") - dr("出库") 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 |
上述代码的第一部分(3到14行),用于在修改某行的产品、入库、出库后,重算从此行开始的所有同产品的行的余额,代码原理已经在上面不区分产品的流水账中介绍,不同的只是在条件表达式中加入了产品比较,请大家自己分析。
第二部分代码(15到29行)的原理:
表事件AfterMoveRow的代码保持不变:
Dim
Key As Decimal表事件DataRowDeleting的代码同样保持不变:
e.DataRow("入库")
= 0
e.DataRow("出库")
= 0
如果多用户同时录入数据,可以在项目事件AfterOpenproject中加入代码:
Dim
drs As
New List(of
DataRow)
With
DataTables("例子二")
For Each
nm As
String In .GetValues("产品")
'找出每个产品的第一行数据,
添加到集合drs中
drs.Add(.Find("产品
= '"
& nm
& "'",
"[_SortKey]"))
Next
For Each
r As
DataRow In
drs
.DataCols("入库").RaiseDataColChanged(r)
'重置每个产品的第一行
Next
End
With
这样打开项目之后,会自动重置每个产品的第一行,刷新每个产品的库存。