ACE DAO 记录集在 vb.net 下返回零字段

问题描述

我正在转换一些在访问中使用 VBA 开发的遗留代码,并使用 DAO 执行数据库查询、更新等。我需要转换一些非 GUI 功能,以便它可以在无人看管的情况下运行,而无需运行 Access。所以我已经将 VBA 代码移植到 VB.net,使用 Access 数据库引擎对象库 (ACE) 提供 DAO 接口。

它在一定程度上有效:在创建和打开(然后关闭)记录集一定(未知)次数后,它开始返回具有正确记录数的记录集,但其 Fields 集合中没有成员。因此,尝试使用 Fields("Name").Value 获取字段的值会引发“在此集合中找不到项目”异常。

这不是特定查询的问题:在某些情况下,具有完全相同参数的完全相同的查询在程序执行的早期运行良好(不更改基础数据)。如果我重新排列程序部分的执行顺序,那么我会在程序的不同部分使用不同的查询得到相同类型的错误(即返回的记录集为空 Fields 集合)。

所以看起来 DAO 库中存在某种错误,在打开和关闭一定数量的记录集后它会失败。但它只发生在 .Net 下,而不是在 VBA 下。

有人遇到过这个问题吗?有什么解决方法吗?

谢谢!

更新:有人要求我发布一些代码。正如我上面所描述的,它不会发生在代码中的特定点 - 我可以根据执行流程在不同的地方发生。这是它发生的地方之一的示例。这是一个从选项表中检索选项值的简单函数

Public Function GetSolverOption(ParameterName As String) As Object
    '
    ' o Gets the value of a solver option.

    Dim dbsjet As Microsoft.Office.Interop.Access.Dao.Database
    Dim qdfControl As Microsoft.Office.Interop.Access.Dao.QueryDef
    Dim rstControl As Microsoft.Office.Interop.Access.Dao.Recordset

    dbsjet = CurrentDB
    qdfControl = dbsjet.QueryDefs("Q_Solver Options")
    qdfControl.Parameters("Q_Parameter").Value = ParameterName
    rstControl = qdfControl.OpenRecordset
    GetSolverOption = rstControl.Fields("Value").Value
    rstControl.Close()
End Function

函数被多次调用而没有任何问题,但随后 GetSolverOption = rstControl.Fields("Value").Value 行开始抛出“Item not found in collection”异常,因为 Fields 集合为空。

解决方法

好的,这是偶然的asp.net吗?还是只是台式机?

在asp.net中?有错误。并且您没有提及您使用的是 .net ODBC 提供程序还是 oleDB 提供程序。您可以随意使用任何一种。

我不知道你是说每次打开一个新连接,还是在启动时创建一个全局连接对象并一遍又一遍地使用它?

我认为你不应该在 .net 中引用或使用 DAO 库(我不知道或认为你是)。如果您 - 不要 - DAO 是不受管理的,会导致内存泄漏。

那么,读取一些数据说成一个表?你可以用这个:

    Dim MyTable As New DataTable

    Using cmdSQL As New OdbcCommand("SELECT ID,FirstName,LastName from tblhotels",New OdbcConnection(My.Settings.TESTAce))
        cmdSQL.Connection.Open()

        MyTable.Load(cmdSQL.ExecuteReader)

    End Using

现在在上面,我们确实创建了一个连接,然后打开它,然后由于代码的“使用块”,它应该被处理和丢弃。但是,如果您使用的是 asp.net,则在打开大约 60 次后 - 它会爆炸。而且你必须在上面添加一个 dispose 命令 - 这是由于 asp.net 的连接池。

所以要解决这个问题,然后:例如:

        MyTable.Load(cmdSQL.ExecuteReader)

        cmdSQL.Dispose

    End Using

在上面?我使用了 ODBC .net 提供程序。如果您使用 oleDB 提供程序(并且您可以),那么上面确实是“相同的”,但是使用 oleDB 提供程序,您会得到:

    Dim MyTable As New DataTable

    Using cmdSQL As New OleDbCommand("SELECT ID,New OleDbConnection(My.Settings.TESTAce))
        cmdSQL.Connection.Open()

        MyTable.Load(cmdSQL.ExecuteReader)

    End Using

所以请注意如何在代码中换出“提供者”。但是,数据表、数据集和数据行等基础对象在所有情况下都是相同的。

其实是因为以上?我实际上会考虑使用 ODBC 提供程序,从那时起您可以交换连接字符串,并说开始使用 SQL 服务器 - 并且代码更改很少。我和 Microsoft 都不建议再针对 sql server 使用 oleDB 提供程序。但他们确实建议 sqprovider(sql server 的本机 .net 提供程序)或 ODBC 仍然得到广泛支持和建议使用的提供程序。

但他们也建议您避免针对 sql server 使用 oleDB。事实上,这些天使用 oleDB 的唯一真正令人信服的理由是什么?如果您仍在使用 Access(ACE/JET 数据引擎),那当然是为什么。

不要太担心上述问题。但是你没有注意到也没有提到你是否每次都使用一个新的连接对象,或者将整个混乱包装在一个 using 块中(它应该为你自动处理连接对象和命令对象。

请注意,虽然我在上面使用了“新连接对象”,但我可以使用预先创建的 oleDB(或 odbc)连接对象,该对象是/是预先创建的 - sql 命令对象接受字符串,或实际上是一个连接对象 - 您的选择。

那么,第一个真正的问题是:您是按照上述方式处理每次使用的连接对象,还是重新使用一个给定的连接对象?我会考虑为整个应用程序一次性创建一个连接对象 - 这可以/将消除连接对象的重新创建和处理。

然而,你肯定不想在没有 using 块的情况下一遍又一遍地创建新的连接对象——或者至少在你的代码中有一个 connection.dispose 。这可以解释随着时间的推移 - 您的代码中的事情开始向南。

编辑: 好的,鉴于我们已经说了一堆代码 - VBA,我们想在 vb.net 中转换 + 使用?

我以前这样做过,转化率还不错。

所以,说拿这个代码片段:

VBA:

  Dim MyDB As Database
  Dim myRST As Recordset
  Set MyDB = CurrentDb()
  dim strSQL as String
  strSQl = "SELECT * from ProjectComponentHeader where ID = MyForm.ProjectCompoentID
  Set myRST = MyDB.OpenRecordset(strSQL,dbOpenDynaset,dbSeeChanges)
  myRST.Edit
  myRST!StPrepress = "WAIT - APPROVAL"
  If Nz(myRST!FirstProofSentDate,0) = 0 Then
      myRST!FirstProofSentDate = Now()
  End If
  myRST!ProofSentDate = Now()
  myRST.Update

那么,要重新考虑上面的因素,比如说使用 .net 中的 oleDB 提供程序?

上面会变成这样:

    Dim da As OleDbDataAdapter
    Dim rst As DataRow
    Dim strSQL As String
    strSQL = "SELECT * from ProjectComponentHeader where ID = " & ProjectCompoentID
    rst = MyrstEdit(strSQL).Rows(0),"",da)

    rst("StPrepress") = "WAIT - APPROVAL"
    If Nz(rst("FirstProofSentDate"),0) = 0 Then
        rst("FirstProofSentDate") = Now()
    End If
    rst("ProofSentDate") = Now()
    da.Update(Myrst)

因此,我构建了一个名为 MyRst 和 MyRstEdit 的例程。他们只是返回一个数据表。

我构建了一个 nz() 函数。

所以,现在,我“更多”地重构代码。我真的不必重新编写现有的代码逻辑 - 只是重新考虑使用 .net 对象。我用一些相当混乱的 VBA 和一些相当长且复杂的例程完成了上述工作。

我的意思是,甚至拉入 VBA 代码,并使用 DAO 对象引用?您仍然必须“检查”代码并重构为 vb.net 代码。正如您所注意到的,这个过程进行得非常快——而且工作量并不大。毫无疑问,转换需要额外的工作——但转换这些例程的工作量并不大——而且不会比你使用 DAO 对象而不是 .net 对象(数据表、数据行和更多稀有数据集)。

因此,我构建了一个 MyRst 和一个 MyRstEdit 函数 - 它们返回一个 .net 数据表。结果,我实际上发现很多例程的代码比以前少了一点,或者至少代码遵循与 VBA 代码相同的逻辑和流程。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...