【问题标题】:Forms bound to updateable ADO recordsets are not updateable when the source includes a JOIN当源包含 JOIN 时,绑定到可更新 ADO 记录集的表单不可更新
【发布时间】:2010-11-07 18:19:11
【问题描述】:

我正在使用 Access 2007 开发一个应用程序。它使用 .accdb 前端连接到 SQL Server 2005 后端。我使用在运行时绑定到 ADO 记录集的表单。为了效率,记录集通常只包含一条记录,在服务器上查询出来:

Public Sub SetUpFormRecordset(cn As ADODB.Connection, rstIn As ADODB.Recordset,      rstSource As String)
Dim cmd As ADODB.Command
Dim I As Long

Set cmd = New ADODB.Command

cn.Errors.Clear

'   Recordsets based on command object Execute method are Read Only!

With cmd
    Set .ActiveConnection = cn
    .CommandType = adCmdText
    .CommandText = rstSource
End With

With rstIn
    .CursorType = adOpenKeyset
    .LockType = adLockPessimistic                           'Check the locktype after   opening; optimistic locking is worthless on a bound
End With                                                    ' form, and ADO might open optimistically without firing an error!

rstIn.Open cmd, , adOpenKeyset, adLockPessimistic           'This should run the query on the server and return an updatable recordset

With cn
    If .Errors.Count <> 0 Then
        For Each errADO In .Errors
            Call HandleADOErrors(.Errors(I))
            I = I + 1
        Next errADO
    End If
End With
End Sub

rstSource(包含记录集所基于的 TSQL 的字符串)由调用例程组装,在这种情况下来自被绑定表单的 Open 事件:

Private Sub Form_Open(Cancel As Integer)
Dim rst As ADODB.Recordset
Dim strSource As String, DefaultSource as String
Dim lngID As Long

lngID = Forms!MyParent.CurrentID

strSource = "SELECT TOP (100) PERCENT dbo.Customers.CustomerID,   dbo.Customers.LegacyID,  dbo.Customers.Active, dbo.Customers.TypeID, dbo.Customers.Category, " & _
"dbo.Customers.Source, dbo.Customers.CustomerName, dbo.Customers.CustAddrID, dbo.Customers.Email, dbo.Customers.TaxExempt, dbo.Customers.SalesTaxCode, " & _
"dbo.Customers.SalesTax2Code, dbo.Customers.CreditLimit, dbo.Customers.CreationDate, dbo.Customers.FirstOrder, dbo.Customers.LastOrder, " & _
"dbo.Customers.nOrders, dbo.Customers.Concurrency, dbo.Customers.LegacyLN, dbo.Addresses.AddrType, dbo.Addresses.AddrLine1, dbo.Addresses.AddrLine2, " & _
"dbo.Addresses.City, dbo.Addresses.State, dbo.Addresses.Country, dbo.Addresses.PostalCode, dbo.Addresses.PhoneLandline, dbo.Addresses.Concurrency " & _
"FROM dbo.Customers INNER JOIN " & _
"dbo.Addresses ON dbo.Customers.CustAddrID = dbo.Addresses.AddrID "
strSource = strSource & "WHERE dbo.Customers.CustomerID= " & lngID

With Me                             'Default is Set up for editing one record
    If Not Nz(.RecordSource, vbNullString) = vbNullString Then
        If .Dirty Then .Dirty = False   'Save any changes on the form
        .RecordSource = vbNullString
    End If

    If rst Is Nothing Then          'Might not be first time through
        DefaultSource = .RecordSource
    Else
        rst.Close
        Set rst = Nothing
    End If
End With

Set rst = New ADODB.Recordset
Call setupformrecordset(dbconn, rst, strSource)    'dbconn is a global variable

With Me
    Set .Recordset = rst
End With

End Sub

从 setupformrecordset 返回的记录集是完全可更新的,它的 .Supports 属性显示了这一点。它可以在代码中进行编辑和更新。

然而,整个表单是只读的,即使它的 .AllowEdits 和 .AllowAdditions 属性都为真。即使是右侧(“多”侧)的字段也无法编辑。

从 TSQL 中删除 INNER JOIN 子句(将 strSource 限制为一个表)使表单完全可编辑。

我已验证 TSQL 包含来自两个表的主键字段,并且每个表都包含一个用于并发的时间戳字段。

我尝试更改记录集的 .CursorType 和 .CursorLocation 属性,但无济于事。

我做错了什么?

【问题讨论】:

  • "虽然 Supports 方法可能为给定的功能返回 True,但它并不能保证提供者可以在所有情况下使该功能可用。 Supports 方法只是返回提供者是否可以支持指定的功能,假设满足某些条件。例如,Supports 方法可能指示 Recordset 对象支持更新,即使游标基于多表连接——其中某些列不可更新。 - msdn.microsoft.com/en-us/library/ms676500%28VS.85%29.aspx
  • 这种代码:“If Not Nz(.RecordSource, vbNullString) = vbNullString Then”让我头疼。为什么不使用“If Not IsNull(.RecordSource)”?如果 .RecordSource 不能为 Null 并且为空时为 ZLS,则 "Len(.RecordSource)=0" 将是正确的测试。

标签: tsql vba ms-access-2007 ado


【解决方案1】:

我在使用 JOIN 操作的 SQL 中遇到了同样的问题。

也许你可以看到这个链接:

http://office.microsoft.com/en-gb/access-help/edit-data-in-a-query-HA010097876.aspx

某些查询不可更新。

所以你解决了这个问题?

【讨论】:

    【解决方案2】:

    我认为您想在记录集上设置 Unique Table 动态属性。

    【讨论】:

    • 感谢您的建议 - 我试过了,但没有任何区别。
    【解决方案3】:

    我发现的一种解决方法是使用“IN”子句。例如:

    SELECT  c.*
    FROM    CATEGORY        c
    WHERE   c.category_id IN (
                SELECT  p.category_id
                FROM    PRODUCT     p
                JOIN    CUST_ORDER  o   ON o.product_id = p.product_id
                WHERE   p.product_type  = 'Widget'
                AND     o.units         > 50
            )
    

    显然,硬编码值可以传递到子例程中(并使用绑定变量)。需要注意的重要一点是 IN 子句可以有任意数量的连接,并且结果集仍然是可更新的。

    如果您需要来自多个表的字段,您可以尝试创建数据库视图和/或使用 DLookup()。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多