在内存中,独立,断开连接的 ADO 记录集

Posted

技术标签:

【中文标题】在内存中,独立,断开连接的 ADO 记录集【英文标题】:In Memory, Stand-Alone, Disconnected ADO Recordset 【发布时间】:2012-05-05 02:53:17 【问题描述】:

当我的表单加载并且我没有收到任何错误消息或代码中断时,我正在我的数据表子表单上运行此代码。我的 debug.print 显示 Recordset rs 充满了应有的 2131 条记录,但我的表单显示了带有 #Name 的单行?在每个领域。我的控件上的控件源属性肯定与我上面列出的字段名称匹配。 RS 是一个表单级变量,在表单关闭之前我不会关闭它或将其设置为空。

知道我做错了什么吗?

Set rs = New ADODB.Recordset
rs.Fields.Append "TimesUsed", adInteger
rs.Fields.Append "strWorkType", adVarWChar, 150
rs.Fields.Append "DateLastUsed", adDate
rs.Fields.Append "SelectedYN", adBoolean
Set rs.ActiveConnection = Nothing
rs.CursorLocation = adUseClient
rs.LockType = adLockBatchOptimistic
rs.Open

Dim sSQL As String
sSQL = "MyComplicated SQL Statement Ommitted from this SO Question"

Dim r As DAO.Recordset
Set r = CurrentDb.OpenRecordset(sSQL, dbOpenDynaset, dbSeeChanges)
If Not (r.EOF And r.BOF) Then
    r.MoveFirst
    Dim fld
    Do Until r.EOF = True
        rs.AddNew
        For Each fld In r.Fields
            rs(fld.Name) = r(fld.Name).value
        Next
        rs.Update
        r.MoveNext
    Loop
End If
r.Close
Set r = Nothing
Debug.Print rs.RecordCount '2131 records
Set Me.Recordset = rs

好的,所以我刚读了this on the MSDN site:

记录集必须包含一个或多个具有唯一索引的字段,例如表的主键。

(注意:此信息在此上下文中似乎是错误的。)

【问题讨论】:

这是一个小表(4 个字段)。但我想我从来没有真正需要为企业开发,所以我习惯于将大量数据(10,000 条记录,有时更多)提取到数据表视图中。在我们的服务器中使用千兆以太网和快速硬盘驱动器,即使我们使用带有 ODBC 链接表的 DAO,我也不会收到用户的任何抱怨。所以,我并没有真正为我的方法辩解,我只是说“到目前为止”它实际上工作得很好。 【参考方案1】:

是否可以在仅作为内存对象的记录集上设置主键?

是的,使用adFldKeyColumn 作为Attrib 到Append Method。阅读FieldAttributeEnum了解更多详情。

如果您的 SQL 语句中已有合适的唯一字段(或字段组合),请使用它。如果没有,请创建一个长整数字段并将其用作假主键字段...为您插入的每一行增加值。

rs.Fields.Append "pkey", adInteger, , adFldKeyColumn

另请参阅 Danny Lesandrini 的 Database Journal 中的这篇文章是否有帮助:Create In-Memory ADO Recordsets

【讨论】:

好的,所以我按照上面的建议添加了一个主键字段,我已经填充了它,但我仍然看到#Name?在我所有的领域。我很困惑。【参考方案2】:

我发现我可以完成这项工作的唯一方法是使用 LockType adLockPessimistic 或 adLockOptimisic。 adLockReadOnly 不工作的原因很明显,并且由于某些原因,adLockBatchOptimistic 不允许记录显示在我的表单中,即使记录集似乎功能齐全。

我还发现您不必为这种类型的断开连接的 Recordset 定义主键即可绑定到表单。我确定您将无法通过表单对记录集进行任何编辑或更新,但在我的测试中,我发现无论如何我都无法对这种类型的表单/记录集进行任何编辑,因为我收到了错误 3270 (与缺少的属性有关)。这真的超出了这个问题的范围。

以下是创建有效的内存记录集所需的最少代码量:

Dim rs As ADODB.Recordset 'Form Level variable

Private Sub Form_Load()
    Set rs = New ADODB.Recordset
    rs.Fields.Append "ID", adInteger
    'Set rs.ActiveConnection = Nothing 'Not Required
    'rs.CursorType = adOpenKeyset 'Not Required
    'rs.CursorLocation = adUseClient 'Not Required
    rs.LockType = adLockPessimistic 'May also use adLockOptimistic
    rs.Open

    Dim i as Integer

    For i = 1 To 10
        rs.AddNew
        rs("ID").Value = i
        rs.Update
    Next i

    Set Me.Recordset = rs
End Sub

在我看来,将表单(在我的例子中为数据表视图)绑定到这种类型的断开连接的记录集对于我的特殊需求来说是一个很好、简单的解决方案。但是,我遇到了几个问题。当您将表单绑定到 ADO 记录集时,默认表单排序似乎不起作用。此外,由于某种原因,我永远无法让这个记录集可编辑/可更新,这是我的需求(我基本上将它用作多检查列表)。如果您从表中获取记录集(即使它是一个空表),然后断开连接,您可以解决此问题。显然,该表提供了我在上面的代码中未能设置的某种结构或属性,根据我尝试添加/编辑记录时收到的 3270 错误消息来判断。而且我还没有弄清楚这些属性是什么或如何设置它们。

总之,我想我会改用 Access“临时”表,因为它不那么复杂,而且没有我上面刚刚列出的问题。

【讨论】:

过去几天,我也有类似的愿望,希望创建一个简单的内存数据集。我也有类似的挫败感,也放弃了。【参考方案3】:

注意:在插入新记录的同时,我能够让一切正常工作 通过使用上面显示的示例 Create In-Memory ADO Recordsets 然后将以下内容更改为表单代码... '注意:诀窍是在 rstADO.Update 之后使用 rstADO.MoveFirst & rstADO.MoveLast

Option Compare Database
Dim rstADO As ADODB.Recordset
Dim lngRecordID As Long

Private Sub Form_BeforeInsert(Cancel As Integer)

    lngRecordID = lngRecordID + 1
    rstADO.AddNew
    rstADO("EmployeeID").value = lngRecordID
    rstADO.Update
    rstADO.MoveFirst
    rstADO.MoveLast

End Sub

Private Sub Form_Load()

    Dim fld As ADODB.Field

    Set rstADO = New ADODB.Recordset
    With rstADO
        .Fields.Append "EmployeeID", adInteger, , adFldKeyColumn
        .Fields.Append "FirstName", adVarChar, 10, adFldMayBeNull
        .Fields.Append "LastName", adVarChar, 20, adFldMayBeNull
        .Fields.Append "Email", adVarChar, 64, adFldMayBeNull
        .Fields.Append "Include", adInteger, , adFldMayBeNull
        .Fields.Append "Selected", adBoolean, , adFldMayBeNull

        .CursorType = adOpenKeyset
        .CursorLocation = adUseClient
        .LockType = adLockPessimistic
        .Open
    End With
    Set Me.Recordset = rstADO

End Sub

Private Sub Form_Unload(Cancel As Integer)

    Set rstADO = Nothing

End Sub

【讨论】:

以上是关于在内存中,独立,断开连接的 ADO 记录集的主要内容,如果未能解决你的问题,请参考以下文章

MS Access ADP 断开连接的记录集恢复

如果外部 ADO 连接已连接或断开,如何检测组件内部?

在 VBA 中对断开连接的 ADODB 记录集应用过滤器

EF中的连接模型和断开模型

bind9+dlz+mysql连接断开问题

AnyDac - 如何断开与内存中的 sqlite db 的连接?