跨表引用的自动更新

上一节提到,如果在订单表的DataColChanged事件中加入如下代码:

If e.DataCol.Name = "品名" Then '如果内容发生变动的是品名列
    If e.NewValue Is Nothing Then '如果新值是空白,也就是品名列的内容为空
        e.
DataRow("单价") = Nothing '那么清空此行单价列的内容
   
Else
        Dim
dr As DataRow
       
'否则在产品表查找同名的产品行,将找到的行赋值给变量dr
        dr =
DataTables("产品").Find("[品名] = '" & e.NewValue & "'")
        If
dr IsNot Nothing Then '如果找到了同名的产品行,也就是dr不是Nothing
            e.
DataRow("单价") = dr("单价")
        End
If
    End
If
End
If

可以实现在订单表中输入品名后,能自动从产品表中找出对应产品的单价,填入到单价列中。
如果修改某一个产品的单价,那么该产品原有订单的单价会保持不变,只有新增的订单才会使用新的单价,这和通过表达式列来引用产品单价是不同的。
可是也有一些场合,可能会要求修改产品单价后,原有订单的产品单价也自动更新。

为此,我们可以在产品表的DataColChanged事件中加入如下代码:

If e.DataCol.Name = "单价"
   
Dim Filter As String = "[品名] = '" & e.DataRow("品名") & "'"
   
Dim drs As List(Of DataRow) = DataTables("订单").Select(Filter)
   
For Each dr As DataRow In drs
       
dr("单价") = e.DataRow("单价")
    Next

End
If

在产品表修改某个产品的单价后,上面的代码会找出订单表中该产品的所有订单,将这些订单的单价设置为新的单价。

我们还可以将前面的代码写得更为简洁:

If e.DataCol.Name = "单价"
   
Dim Filter As String = "[品名] = '" & e.DataRow("品名") & "'"
   
DataTables("订单").ReplaceFor("单价", e.NewValue, Filter)
End If

不过我个人更喜欢第一种写法,虽然代码长了那么一点,但似乎也更容易理解那么一点。

再次提示一下,在上面的DataColChanged事件中,e.NewValue等于e.DataRow("单价"),因为此时新的单价已经写入表中。

所以下面这行代码:

DataTables("订单").ReplaceFor("单价", e.NewValue, Filter)

完全等效于:

DataTables("订单").ReplaceFor("单价", e.DataRow("单价"), Filter)

有条件的跨表更新

上面已经介绍了如何实现跨表引用的自动更新,可是更新有的时候是有条件的,否则还不如直接使用表达式列来引用产品单价。
例如希望在产品表中修改单价后,订单表中已经付款的订单,继续保持原单价不变,而未付款的订单采用新的单价。
为此,我们可以在产品表的
DataColChanged事件中加入如下代码:

If e.DataCol.Name = "单价"
   
Dim Filter As String = "[品名] = '" & e.DataRow("品名") & "' And 已付款 = False"
   
DataTables("订单").ReplaceFor("单价", e.NewValue, Filter)
End If

再例如希望在产品表中修改单价后,对于已经锁定或者已经付款的订单,单价保持不变,其余订单则采用新的单价:

If e.DataCol.Name = "单价"
    Dim
Filter As String = "[品名] = '" & e.DataRow("品名") & "' And 已付款 = False"
    Dim
drs As List(Of DataRow) = DataTables("订单").Select(Filter)
    For Each
dr As DataRow In drs
        If dr.Locked = False Then   

            DataTables(
"订单").DataCols("品名").RaiseDataColChanged(dr)
        End If       

    Next
End If

多列跨表更新

如果订单表有多列数据来自于产品表,一样可以采用类似的设计实现跨表更新。
例如,假定产品表和订单表通过产品编号联系起来(不一定建立了关联),订单表输入产品编号后,品名、型号、规格、单价四列内容从产品表自动继承输入。
为实现此目的,首先订单表
的DataColChanged事件代码应设置为:

If e.DataCol.Name = "产品编号" Then
    If e.NewValue Is Nothing Then
        e.
DataRow("品名") = Nothing
        e.
DataRow("型号") = Nothing
        e.
DataRow("规格") = Nothing
        e.
DataRow("单价") = Nothing
    Else
       
Dim dr As DataRow
        dr =
DataTables("产品").Find("[产品编号] = '" & e.NewValue & "'")
        If
dr IsNot Nothing

            e.
DataRow("品名") = dr("品名")
            e.
DataRow("型号") = dr("型号")
            e.
DataRow("规格") = dr("规格")
            e.
DataRow("单价") = dr("单价")
        End
If
   
End If
End
If

现在希望在产品表修改上述四列数据后,订单表能够自动更新这些列的数据,为此可以将产品表的DataColChanged事件设置为:

Select Case e.DataCol.Name
    Case
"品名","型号","规格",
"单价"
       
Dim Filter As String = "[产品编号] = '" & e.DataRow("产品编号") & "'"
       
Dim drs As List(Of DataRow) = DataTables("订单").Select(Filter)
        For
Each dr As DataRow In
drs
            dr(e.
DataCol.Name) = e.NewValue
        Next
End
Select

或者:

Select Case e.DataCol.Name
    Case
"品名","型号","规格",
"单价"
       
Dim Filter As String = "[产品编号] = '" & e.DataRow("产品编号") & "'"
        DataTables("订单").ReplaceFor(e.DataCol.Name, e.NewValue, Filter)
End
Select

可以看到不管是单列还是多列,自动更新的代码都一样的简洁。

关联表下的编码

不管是产品表和订单表之间是否建立了关联,本节之前所讲述的代码,均是适用的。
如果产品表和订单表之间已经建立了关联,那么代码可以写得稍微简洁一些,因为可以用
GetChildRows获得某个产品的所有订单,用GetParentRow获得某个订单对应的产品

示例

假定产品表和订单表通过产品编号建立了关联,订单表输入产品编号后,品名、型号、规格、单价四列内容从产品表自动继承输入。
为实现此目的,首先订单表
的DataColChanged事件代码应设置为:

If e.DataCol.Name = "产品编号" Then
    If e.NewValue Is Nothing Then
        e.
DataRow("品名") = Nothing
        e.
DataRow("型号") = Nothing
        e.
DataRow("规格") = Nothing
        e.
DataRow("单价") = Nothing
    Else
       
Dim dr As DataRow
        dr =
e.DataRow.GetParentRow("产品")
        If
dr IsNot Nothing

            e.
DataRow("品名") = dr("品名")
            e.
DataRow("型号") = dr("型号")
            e.
DataRow("规格") = dr("规格")
            e.
DataRow("单价") = dr("单价")
        End
If
   
End If
End
If

现在希望在产品表修改上述四列数据后,订单表能够自动更新这些列的数据,为此可以将产品表的DataColChanged事件设置为:

Select Case e.DataCol.Name
    Case
"品名","型号","规格",
"单价"
        Dim drs As List(Of DataRow) = e.DataRow.GetChildRows("订单"))
        For
Each dr As DataRow In
drs
            dr(e.
DataCol.Name) = e.NewValue
        Next
End
Select

上面的代码只是作为多列继承的一个例子而已,因为既然已经建立了关联,那么对于订单表中那些始终和产品表对应列内容保持一直的列,如品名、型号、规格等列,显然用表达式列更为合适;通常只有单价这种可能和产品表对应列内容有差异的列,才会考虑使用数据列,通过代码来计算的。


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