用Table控件模拟关联表

其实不管是双向生成还是单向生成,都会产生关联表,对于性能有一定程度的影响,只是双向生成的时候尤甚。
所以要追求极致的性能,最好是在设置关联的时候,将关联表生成模式选择为“无”。
但是关联表确实给我们带来了很大的便利,我们岂能因噎废食?
可否鱼和熊掌兼得,既可以得到关联表的好处,又不影响性能呢?
完全可以,这就是本节要介绍的内容。

请首先请打开CaseStudy目录下的文件:模拟关联表.Table

该文件的产品表和订单表之间正常建立了关联, 所以可以充分享受关联带来的好处,例如使用表达式来统计和引用数据,在代码中使用GetParentRowGetChildRows方法快捷定位或筛选出关联行。
由于在建立这个关联的时候,关联表的生成模式选择了“无”,不会像常规那样自动创建和显示关联表,所以此关联的存在,对于性能几乎没有影响。
但是我们用窗口和Table控件模拟了一个关联表,打开此窗口后,如果在产品表选择某产品,窗口中的Table控件可以自动显示出该产品的所有订单,表现得就像真的关联表一样。
由于这个“关联表”是模拟的,平时并不存在,打开窗口的时候出现,关闭窗口的时候自动消失,所以这个“关联表”对于性能的影响极微。

设计步骤:

1、在产品表和订单表之间建立关联,关联名为"po",注意关联表生成模式要选择为“无”:

2、在产品表新建一个窗口,窗口类型为停靠,停靠位置为底端。

3、插入一个Table控件,绑定到订单表,将其“作为副本”属性设置为True,“允许编辑”属性设置为True,“停靠”属性设为Fill。

4、窗口的AfterLoad事件设为:

Dim t As Table = Tables("窗口1_Table1")
With
Tables("产品")
    If
.Current Is Nothing Then
        t.Filter =
"False"
   
Else
        t.Filter =
"产品编号 = " & .Current("产品编号")
    End
IF
End
With

此段代码确保打开窗口后,Tables("窗口1_Table1")只显示当前选定产品的订单。

5、关闭窗口设计器,回到产品表,打开表属性设置窗口,将其CurrentChanged事件代码设为:

If Forms("窗口1").Opened() '一定要判断用于模拟关联表的窗口是否已经打开
    Dim
t As Table = Tables("窗口1_Table1"
)
    With
Tables("产品"
)
        If
.Current Is Nothing
Then
            t.Filter =
"False"
       
Else
            t.Filter =
"产品编号 = " & .Current("产品编号")
        End
IF
   
End With
End
If

当我们在产品表选择不同的产品时,上述代码会判断窗口是否已经打开, 如果已经打开,则更新Tables("窗口1_Table1")的Filter属性,使其显示新选定产品的订单。

6、将订单表的DataRowAdding事件代码设置为:

If CurrentTable.Name = "窗口1_Table1" Then '如果当前表是模拟的关联表
   Dim r As Row = Tables("产品").Current
   If r IsNot Nothing Then
        e.DataRow("产品编号") = r("产品编号")
   End
If

End
If

当我们选择这个模拟的关联表,然后单击菜单中的增加行按钮时,上述代码会检查产品表中是否有选定行,如果有则新增订单自动继承此选定产品的产品编号。
如果没有这段代码,在模拟的关联表增加行时,新增行是看不见的,因为新增行的产品编号为空,而模拟的关联表只显示产品编号为选定产品的订单。

至此,我们用窗口的Table控件模拟出来的关联表,和真正的关联表一样,能够动态显示选定产品的订单,新增行也能自动继承选定产品的产品编号,不同的只是这个“关联表”的名称是
Tables("窗口1_Table1"),而不是Tables("产品.订单")。

7、在产品表增加两个表达式列,分别为总销售量和总销售金额,总销售量的表达式:Sum(Child(po).数量),总销售金额的表达式为:Sum(Child(po).金额)

8、将订单表的DataColChanged事件代码设置为:

Select Case e.DataCol.Name
    Case "产品编号"
        Dim pr As DataRow = e.DataRow.GetParentRow("产品")
        If pr IsNot Nothing Then
            e.DataRow("单价") = pr("单价")
        End
If

End
Select

这样在订单表输入产品编号,会自动从产品表中找出对应的产品,然后取其单价填入到订单表的单价列中。

9、将产品表的DataColChanged事件代码设置为:

If e.DataCol.Name = "单价" Then '更新未确认订单的单价
    Dim drs As List(of DataRow)
    drs = e.DataRow.GetChildRows("订单")
   
For Each dr As DataRow In drs
       
If dr("确认") = False Then
            dr("单价") = e.DataRow("单价")
        End If
   
Next

End
If

这样在产品表修改某产品的单价,系统会找出订购此产品的全部订单,然后并将未确认订单的单价更新为新的单价。

一点提示:

我们没有必要将关联表视为洪水猛兽,只有确实因为关联表过多,对性能有严重影响时,才可以考虑编码模拟关联表。


本页地址:http://www.foxtable.com/webhelp/topics/2222.htm