【问题标题】:ADODB Recordset from Access VBA to a SQL Server fails to update a Boolean field from true to false从 Access VBA 到 SQL Server 的 ADODB 记录集无法将布尔字段从 true 更新为 false
【发布时间】:2022-12-15 13:48:05
【问题描述】:

我正在维护在 Windows 10 和 11 上使用 Access 365 运行时(32 位)的设备上运行的 Access 365 数据库(32 位)。后端使用 Microsoft SQL Server Express(64 位)版本 15.0.4198.2 , 在 AWS RDS 上。对于一个功能,该代码使用 ADODB 2.8(VBA 参考是Microsoft ActiveX Data Objects 2.8 Library)打开一个记录集,连接到一个表,并修改一些字段。

在我包含一行代码将 boolean 字段从 true 切换到 false 之前,代码工作得很好。进行此更改后,代码将抛出错误 #-2147217864,描述为 Row cannot be located for updating. Some values may have been changed since it was last read.。我将代码隔离到单元测试并确保没有其他代码行更改记录集,但代码仍然抛出错误。

这是单元测试,其中显示了一些辅助函数,但未包含在内:

Private Sub TestRelistingDataChangeProcess()
    On Error GoTo TestFail
    
    Dim itemSku As String
    itemSku = "1234"
       
    Dim verifySql As String
    verifySql = StrFormat("SELECT failedImport FROM dbo.myTable WHERE SKU = '{0}'", itemSku)

    Dim rsSql As String
    rsSql = StrFormat("UPDATE dbo.myTable SET failedImport = 0 WHERE SKU = '{1}'", itemSku)
    ExecuteCommandPassThrough rsSql
    
    rsSql = "PARAMETERS SKU Text ( 255 ); SELECT * FROM myTable WHERE SKU=[SKU]"
    
    Dim cmd As ADODB.Command
    Set cmd = New ADODB.Command
    cmd.ActiveConnection = GetCurrentConnection()
    cmd.CommandText = rsSql

    Dim param As ADODB.Parameter
    Set param = cmd.CreateParameter(Name:="[SKU]", Type:=adLongVarChar, Value:=itemSku, Size:=Len(itemSku))
    cmd.Parameters.Append param

    Dim rs As ADODB.Recordset
    Set rs = New ADODB.Recordset
    rs.Open cmd, , adOpenDynamic, adLockOptimistic

    With rs
        Debug.Print "1. Setting field to TRUE."
        .Fields("failedImport") = True
        .Update
        Assert.IsTrue ExecuteScalarAsPassThrough(verifySql)

        Debug.Print "2. Setting field to FALSE."
        .Fields("failedImport") = False
        .Update
        Assert.IsFalse ExecuteScalarAsPassThrough(verifySql)
    End With
    
    Assert.Succeed

TestExit:
    Exit Sub

    TestFail:
    Assert.Fail "Test raised an error: #" & Err.Number & " - " & Err.Description
    Resume TestExit
End Sub

搜索有关此错误的信息导致许多可能性,并不是所有的都在 VBA 中。我知道带有可为空布尔字段的 Access 和 SQL Server 表存在问题,因此我验证了 SQL Server 表具有该字段的默认值。打开记录集时,我尝试了许多 CursorTypeLockType 组合。没有工作。

我做错了什么导致抛出这个错误?我该怎么做才能更改代码以使其正常工作?

【问题讨论】:

    标签: sql-server vba ms-access adodb


    【解决方案1】:

    经过认真的搜索和测试,我找到了this blog post,其中包含[9 Nov 2009 8:49] Tonci Grgin帖子中的这一行: rsCustomers.Properties("Update Criteria").Value = adCriteriaKey

    我不认识 adCriteriaKey 枚举,所以我搜索、找到并阅读了 this MS documentation page。这个枚举系列“指定在使用 Recordset 对象对数据源的一行进行乐观更新期间,哪些字段可用于检测冲突。”具体来说,adCriteriaKey 值“如果数据源行的键列已更改,则检测到冲突,这意味着该行已被删除。”

    通过一些测试和调试语句,我了解到我打开的记录集默认使用adCriteriaUpdCols。如果与 Recordset 的更新字段相对应的数据源行的任何列已更改,则此值“检测到冲突”。无论出于何种原因,ADODB 都会在不应该存在冲突的情况下识别出冲突。我想知道该错误是否与使用 -1 作为 true 的 VBA 有关,而 SQL Server 使用 1,但基于 this SO post 似乎并非如此。 我也不知道为什么以前版本的代码在将布尔字段从 false 更改为 true 而不是从 true 更改为 false 时起作用。也许有一种方法可以跟踪 ADODB 代码并确定这里到底出了什么问题,但我还不知道该怎么做。我已经在这个错误上花费了 HOURS,所以我需要继续……:-)

    因此,这是我为使一切正常而添加的代码行:

    Dim rs As ADODB.Recordset
    Set rs = New ADODB.Recordset
    rs.Open cmd, , adOpenDynamic, adLockOptimistic
    rs.Properties("Update Criteria").Value = adCriteriaKey  ' <----- NEW LINE HERE
    

    请注意,只有当您的表包含主键并且您在 Recordset 中使用它时,此行才适用。此外,another forum post 展示了 adCriteriaKey 挽救了这一天。

    我希望这篇文章对其他人有意义,并有助于在将来的某个时候拯救某人!如果不出意外,这对我来说是一个很好的锻炼。 :-)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-01-26
      • 2017-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-11-01
      相关资源
      最近更新 更多