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

ACE DAO recordsets returning zero fields under vb.net

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

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

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

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

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

谢谢!

更新:有人问我 post 一些代码。正如我上面所描述的,它不会发生在代码中的特定点——我可能会发生在不同的地方,具体取决于执行流程。这是它发生的地方之一的示例。从 table 个选项中检索选项值是一个简单的函数:

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 行开始抛出“在集合中找不到项目”异常,因为字段集合是空的。

好的,这是偶然的吗asp.net?或者只是桌面?

在asp.net?有错误。而且您没有提及您是使用 .net ODBC 提供程序还是 oleDB 提供程序。您可以随意使用其中一个。

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

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

所以,要读取一些数据说成table?你可以使用这个:

    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 次打开后 - 它会爆炸。并且您必须添加到上面的处置命令 - 这是由于 asp.net.

的连接池

所以要解决这个问题,then:eg:

        MyTable.Load(cmdSQL.ExecuteReader)

        cmdSQL.Dispose

    End Using

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

    Dim MyTable As New DataTable

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

        MyTable.Load(cmdSQL.ExecuteReader)

    End Using

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

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

但他们还建议您避免使用 oleDB 来对抗 sql 服务器。事实上,现在使用 oleDB 的唯一真正令人信服的理由是什么?为什么当然,如果您仍在使用 Access(ACE/JET 数据引擎)。

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

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

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

但是,您肯定不想在没有 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 的例程。他们只是return一个数据table.

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

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

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

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