【问题标题】:Do Until issues in VB6VB6 中的直到问题
【发布时间】:2018-03-27 15:16:11
【问题描述】:

我在 VB6 中遇到了一些问题。其中 2 个问题似乎是由我使用 Do Until 循环引起的。

这些问题来自以下代码

Dim strAccount As String

On Error GoTo PayBalance_Err

If dtaEmployees.Recordset.RecordCount = 0 Then
    Exit Sub
End If

If MsgBox("Are you sure you would like to pay all outstanding balances? This change cannot be undone.", vbYesNo, "Confirm") = vbNo Then
    Exit Sub
Else

    Screen.MousePointer = vbHourglass

    dtaEmployees.Recordset.MoveFirst

    If dtaEmployees.Recordset.RecordCount > 0 Then
        Do Until dtaEmployees.Recordset.EOF

           dbsPeriod.BeginTrans

           strAccount = dtaEmployees.Recordset.Fields(1)

           If GotBatch = False Then
               Batch_Number = Get_Batch_Number()
               Batch_Line = 0
               GotBatch = True
           End If

           Batch_Line = Batch_Line + 1

           Dim rs As DAO.Recordset
           sql = "SELECT * FROM [Ledger Transactions] WHERE [Account_Code] = '" & strAccount & "' AND [Outstanding] > 0"
           Set rs = dbsPeriod.OpenRecordset(sql, dbOpenDynaset)

           sql = "UPDATE [Ledger] SET [Sales_Balance] = 0, [Date_Last_Cash_S] = " & Format(Now, "dd/MM/yyyy") & " WHERE Account_Code = '" & strAccount & "'"
           dbsPeriod.Execute sql

           sql = "UPDATE [Ledger Transactions] SET [Outstanding] = 0 WHERE [Account_Code] = '" & strAccount & "'"
           dbsPeriod.Execute sql

           Dim GoodsValue, VAT, TotalValue As Currency
           GoodsValue = dtaEmployees.Recordset.Fields(3) / 1.2
           VAT = GoodsValue / 5
           TotalValue = dtaEmployees.Recordset.Fields(3)

           Dim pPeriod, pYear As String
           pPeriod = Mid(DB_Period_Name$, Len(DB_Period_Name$) - 7, 2)
           pYear = Mid(DB_Period_Name$, Len(DB_Period_Name$) - 5, 2)

           sql = "INSERT INTO [Ledger Transactions]([Batch_Number], [Batch_Line], [Account_Code], [Reference], [Description], [Goods_Value], " & _
                 "[VAT_Value], [Total_Value], [Outstanding], [Document_Date], [Period], [Year], [Type], [Sort_Order]) VALUES(" & Batch_Number & ", " & _
                 Batch_Line & ", '" & strAccount & "', 'PAYROLL', '" & txtDescription.Text & "', " & GoodsValue & ", " & VAT & ", " & TotalValue & _
                  ", 0, " & Format(Now, "dd/MM/yyyy") & ", '" & pPeriod & "', '" & pYear & "', 'P', 1)"

           dbsPeriod.Execute sql

           rs.MoveFirst

           Dim TotalPayment As Currency
           TotalPayment = 0

           Do Until rs.EOF
              TotalPayment = TotalPayment + rs.Fields(10)

              rs.MoveNext
           Loop

           rs.MoveFirst

           Do Until rs.EOF
              GoodsValue = rs.Fields(8)
              VAT = rs.Fields(9)

              sql = "INSERT INTO [Allocations]([Payment], [Account_Code], [Sales_Or_Purchase], [Payment_Batch_Number], [Payment_Batch_Line], " & _
                    "[Payment_Reference], [Payment_Date], [Payment_Value], [Invoice_Batch_Number], [Invoice_Batch_Line], [Invoice_Type], [Invoice_Date], " & _
                    "[Invoice_Goods], [Invoice_VAT], [Date_Allocated], [Who_Allocated], [Goods_Allocated], [Discount], [VAT_Allocated]) " & _
                    "VALUES(True, '" & strAccount & "', False, " & Batch_Number & ", " & Batch_Line & ", 'PAYROLL', " & _
                    Format(Now, "dd/MM/yyyy") & ", " & rs.Fields(10) & ", " & Batch_Number & ", " & Batch_Line & ", 'I', " & _
                    Format(Now, "dd/MM/yyyy") & ", " & GoodsValue & ", " & VAT & ", " & Format(Now, "dd/MM/yyyy") & ", '" & User_ID$ & "', " & _
                    GoodsValue & ", 0, " & VAT & ")"

              dbsPeriod.Execute sql

              sql = "INSERT INTO [Audit Header]([Batch_Number], [Batch_Line], [Account_Code], [Sales_Or_Purchase], [Type], [Reference], " & _
                    "[Description], [Goods_Value], [VAT_Value], [Total_Value], [Document_Date], [VAT_Percentage_1], [Goods_1], [VAT_1], " & _
                    "[Post_Date], [Who_Posted], [SOPS_Provisional_Due]) " & _
                   "VALUES(" & Batch_Number & ", " & Batch_Line & ", '" & strAccount & "', False, 'I', 'PAYROLL', '" & txtDescription.Text & "', " & _
                   GoodsValue & ", " & VAT & ", " & rs.Fields(10) & ", " & Format(Now, "dd/MM/yyyy") & ", 20, " & GoodsValue & ", " & VAT & _
                   ", " & Format(Now, "dd/MM/yyyy") & ", '" & User_ID$ & "', " & Format(Now, "dd/MM/yyyy") & ")"

              dbsPeriod.Execute sql

              rs.MoveNext
           Loop

           rs.MoveFirst

           sql = "INSERT INTO [Allocations]([Payment], [Account_Code], [Sales_Or_Purchase], [Payment_Batch_Number], [Payment_Batch_Line], " & _
                "[Payment_Reference], [Payment_Date], [Payment_Value], [Invoice_Batch_Number], [Invoice_Batch_Line], [Invoice_Type], [Invoice_Date], " & _
                "[Invoice_Goods], [Invoice_VAT], [Date_Allocated], [Who_Allocated], [Goods_Allocated], [Discount], [VAT_Allocated]) " & _
               "VALUES(True, '" & strAccount & "', False, " & Batch_Number & ", " & Batch_Line & ", 'PAYROLL', " & _
               Format(Now, "dd/MM/yyyy") & ", " & rs.Fields(10) & ", " & Batch_Number & ", " & Batch_Line & ", 'P', " & _
               Format(Now, "dd/MM/yyyy") & ", " & GoodsValue & ", " & VAT & ", " & Format(Now, "dd/MM/yyyy") & ", '" & User_ID$ & "', " & _
                GoodsValue & ", 0, " & VAT & ")"

             dbsPeriod.Execute sql

             sql = "INSERT INTO [Audit Header]([Batch_Number], [Batch_Line], [Account_Code], [Sales_Or_Purchase], [Type], [Reference], " & _
                   "[Goods_Value], [Total_Value], [Document_Date], " & _
                  "[Post_Date], [Who_Posted], [SOPS_Provisional_Due]) VALUES(" & Batch_Number & ", " & Batch_Line & ", '" & strAccount & _
                  "', False, 'P', 'Payment', " & rs.Fields(10) & ", " & rs.Fields(10) & ", " & _
                  Format(Now, "dd/MM/yyyy") & ", " & Format(Now, "dd/MM/yyyy") & ", '" & User_ID$ & "', " & _
                 Format(Now, "dd/MM/yyyy") & ")"

             dbsPeriod.Execute sql

             sql = "INSERT INTO [Audit Lines]([Batch_Number], [Batch_Line], [Batch_Line_Item], [Account_Code], [Sales_Or_Purchase], " & _
                  "[Nominal_Code], [Reference], [Description], [Goods_Value], [VAT_Value])" & _
                " VALUES(" & Batch_Number & ", " & Batch_Line & ", 1, '" & strAccount & "', False, '" & Cmb_Code.Text & "'" & _
                 ", 'PAYROLL', '" & txtDescription.Text & "', " & GoodsValue & ", " & VAT & ")"

             dbsPeriod.Execute sql

             dbsPeriod.CommitTrans

             dtaEmployees.Recordset.MoveNext
        Loop
    End If
End If

Screen.MousePointer = vbDefault

MsgBox "Payment(s) complete!", vbOKOnly, "Success"

dtaEmployees.Refresh

grdEmployees.Redraw = True

Exit Sub

PayBalance_Err:

   Screen.MousePointer = vbDefault

   MsgBox "An error has occurred. " & err.Description, vbCritical, "Error"
   dbsPeriod.Rollback

在我的测试数据中,dtaEmployees.Recordset.RecordCount 为 2。循环的第一次迭代工作正常,数据使用事务正确插入。

但是,循环的第二次迭代存在一些问题。

首先是没有设置交易。每个 SQL 语句都是单独执行的,在我的错误陷阱中我调用 dbsPeriod.Rollback 并且有一个错误说

您尝试在未先使用 BeginTrans 的情况下提交或回滚事务

但是,我是在代码的第 3 行设置事务?

第二个问题发生在此之前。我收到以下消息

发生了错误。对象无效或不再设置。

当代码到达rs.MoveFirst 行时。 rs 记录集再次被设置在循环的顶部,所以我不确定为什么它说它不是? rs 没有在这两行之间使用,所以我不确定为什么会出错?肯定有与该查询匹配的数据,因为我已在 Access 本身中运行它。

如果有人能够帮助我解决其中一个问题,我将不胜感激,我已经为此困扰了好几个小时。

【问题讨论】:

    标签: loops transactions vb6 iteration recordset


    【解决方案1】:

    对于第一个错误,事务在循环内开始并提交。而不是这个:

    If dtaEmployees.Recordset.RecordCount > 0 Then    
        Do Until dtaEmployees.Recordset.EOF
            dbsPeriod.BeginTrans
    
            '... 
    
            dbsPeriod.CommitTrans
            dtaEmployees.RecordSet.MoveNext
        Loop
    End If
    

    你可能想要这个:

    If dtaEmployees.Recordset.RecordCount > 0 Then
        dbsPeriod.BeginTrans
        Do Until dtaEmployees.Recordset.EOF
    
            '... 
    
            dtaEmployees.RecordSet.MoveNext
        Loop
        dbsPeriod.CommitTrans
    End If
    

    除此之外,示例中不包含问题中提到的 ROLLBACK 代码,所以我只能建议这些代码。

    此外,我强烈怀疑整个事情可以简化为对数据库的一次调用,完全消除循环的需要。

    对于第二个问题,被跳过的代码很重要。要么是有什么东西打破了记录集,要么是记录集一开始就失败了。如果您使用的是On Error Resume Next,您应该停止。它隐藏了你的错误,使调试变得困难。

    最后,SQL 字符串的构建方式非常容易受到注入攻击。我希望您非常确定您的数据源,以这种糟糕的方式构建 SQL 字符串。了解如何使用 ADO.Parameter 对象。

    【讨论】:

    • 我需要循环内的交易,因为代码会遍历系统中的每个员工并更新他们的购买历史记录。每个客户可能有多次购买,这就是为什么我希望每个客户进行一次交易,因为如果一次购买的更新失败,它只会对该员工失败,而不是整个过程 - 这有意义吗?
    • 我已将完整的子程序添加到问题中,以防有助于更轻松地理解和解决问题。
    • 这有点道理。我仍然会尝试减少到​​数据库的总往返次数。您是否知道可以在一个 .Execute 调用中一起训练多个 SQL 命令? :sql = "UPDATE x SET y = 1;UPDATE a SET b = 2;" 这样做,事情会运行得更快,而且你会得到一个隐式事务(少得多的代码)。
    • 那么,sql = 然后附上我所有的声明,用 ; 分隔,每个声明都有一个唯一的 ID(例如 UPDATE a; UPDATE b;)?
    • ab 只是占位符,因此您可以在同一个 sql 命令中看到类似于两个完整查询的内容。
    【解决方案2】:

    虽然它不能解决您的事务问题(您确定您只打开了一个数据库吗?),但RecordSet 问题可能会通过在每个循环结束时添加rs.Close 来解决。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-31
      • 2012-01-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多