VB6 ADODB.Recordset RecordCount 属性总是返回 -1

Posted

技术标签:

【中文标题】VB6 ADODB.Recordset RecordCount 属性总是返回 -1【英文标题】:VB6 ADODB.Recordset RecordCount property always returns -1 【发布时间】:2011-01-17 23:12:59 【问题描述】:

我正在尝试让一些旧的 VB6 代码与 SQL Server Compact 一起使用。

我可以连接,打开数据库,一切似乎都很好。我可以运行有效的插入选择命令。

但是 ADODB.Recordset RecordCount 属性总是返回 -1,即使我可以访问字段并查看数据。更改 CursorLocation = adUseClient 会导致执行 SQL 时出现问题(多步操作产生错误)。

Option Explicit
    Private Const mSqlProvider          As String = "Provider=Microsoft.SQLSERVER.CE.OLEDB.3.5;"
    Private Const mSqlHost              As String = "Data Source=C:\Database.sdf;"
    Private mCmd                        As ADODB.Command   ' For executing SQL
    Private mDbConnection               As ADODB.Connection


Private Sub Command1_Click()


   Dim rs As ADODB.Recordset

    Set rs = New ADODB.Recordset


    Dim DbConnectionString As String

    DbConnectionString = mSqlProvider & _
                            mSqlHost


    Set mDbConnection = New ADODB.Connection
    mDbConnection.CursorLocation = adUseServer

    Call mDbConnection.Open(DbConnectionString)

    If mDbConnection.State = adStateOpen Then
        Debug.Print (" Database is open")
        ' Initialise the command object
        Set mCmd = New ADODB.Command
        mCmd.ActiveConnection = mDbConnection

        mCmd.CommandText = "select * from myTestTable"
        mCmd.CommandType = adCmdText

        Set rs = mCmd.Execute

        Debug.Print rs.RecordCount  ' Always returns -1  !!
        Debug.Print rs.Fields(0)   ' returns correct data for first row, first col
        Debug.Print rs.Fields(1)   ' returns correct data for first row, 2nd col
        Debug.Print rs.Fields(2)   ' returns correct data for first row, 3rd col

    End If

End Sub

我们将不胜感激地接受任何建议。

【问题讨论】:

【参考方案1】:

实际上CursorLocation 在这种情况下起了主要作用。使用rs.CursorLocation = adUseClient设置光标位置,试一试。

    Set rs = New ADODB.Recordset
    rs.CursorLocation = adUseClient
    Dim DbConnectionString As String

    DbConnectionString = mSqlProvider & _
                            mSqlHost


    Set mDbConnection = New ADODB.Connection
    mDbConnection.CursorLocation = adUseServer

    Call mDbConnection.Open(DbConnectionString)

    If mDbConnection.State = adStateOpen Then
        Debug.Print (" Database is open")
        ' Initialise the command object
        Set mCmd = New ADODB.Command
        mCmd.ActiveConnection = mDbConnection

        mCmd.CommandText = "select * from myTestTable"
        mCmd.CommandType = adCmdText

        Set rs = mCmd.Execute

        Debug.Print rs.RecordCount  ' This should now return the right value.
        Debug.Print rs.Fields(0)   ' returns correct data for first row, first col
        Debug.Print rs.Fields(1)   ' returns correct data for first row, 2nd col
        Debug.Print rs.Fields(2)   ' returns correct data for first row, 3rd col

    End If

End Sub

【讨论】:

虽然 CursorLocation 驱动行为,但它同样取决于您使用的驱动程序。实际上 rs.CursorLocation = adUseClient 允许使用驱动程序的光标。有关光标功能,请参阅您正在使用的驱动程序文档 (Microsoft.SQLSERVER.CE.OLEDB.3.5)。 CE 驱动程序可能不提供它。在这种情况下,您可能会寻找升级的驱动程序。 能否也设置连接对象的 CursorLocation 属性? 设置为 aduseserver THE CONNECTION 而不是记录集。使用新的/其他连接【参考方案2】:

这是用于访问数据的游标类型的结果,这篇文章涵盖了问题和可能的修复。

http://www.devx.com/tips/Tip/14143

编辑

我很抱歉没有更注意您与 Compact 打交道的事实。使用 Compact 时,情况与我提到的情况类似,因为它默认使用仅向前游标(不支持行计数),但还有其他两种可用的游标类型,如下面的链接中所述。

http://support.microsoft.com/kb/272067

【讨论】:

尝试了这两种方法,但都未能执行“select * from myTestTable”。顺便说一句,如果我通过 Sql Server Management Studio 2008 打开 sdf,则 sql 可以工作并返回 11 行。【参考方案3】:

从很久以前使用 VB6/ADO 的内存中,.RecordCount 字段不会返回有意义的数据,直到您移动到记录集的末尾。

rs.MoveLast
rs.MoveFirst
Debug.Print rs.RecordCount

尽管如此,您需要确保您具有适当的光标类型(即,不仅仅是向前)。

我能想到的唯一其他解决方案是执行单独的 SELECT COUNT(*) FROM myTestTable 等,但这会导致该调用与实际返回行的调用之间的数据发生变化。

【讨论】:

【参考方案4】:

对于 Compact,默认光标属性是 adOpenForwardOnly 以提高性能。因此,RecordCount 返回为“-1”,这意味着它不可用,而不是空白。这是设计使然,因为动态游标中的记录数可能会更改并导致在客户端服务器之间来回 ping 以保持准确性。但是,如果记录数很重要,请尝试将其设置为使用带有服务器端游标的 adOpenKeyset 或 adOpenStatic。

【讨论】:

【参考方案5】:

检查记录集属性

以下是com.status.live代码返回的RecordCount值的结果

+------------------+-------------------+-------------+---------------+--------------+
|    CursorTypeEnum|adOpenForwardOnly=0|dOpenKeyset=1|adOpenDynamic=2|adOpenStatic=3|
|CursorLocationEnum|                                                                |
+------------------+-------------------+-------------+---------------+--------------+
|adUseServer = 2   |         X         |      O      |       X       |       O      |
|adUseClient = 3   |         O         |      O      |       O       |       O      |
+------------------+-------------------+-------------+---------------+--------------+

【讨论】:

【参考方案6】:

这是我使用的解决方案

Dim recordnumber As Long
Dim SalRSrec As New ADODB.Recordset
Set SalRSrec = Nothing
SalRSrec.Open ("SELECT count(*) from SALARY where EMPID= '" & cmb_empid & "' ;"), Dbase, adOpenKeyset, adLockOptimistic
recordnumber = SalRSrec.GetString
MsgBox recordnumber

【讨论】:

【参考方案7】:

Set rs = mCmd.Execute 替换为:

set rs = new ADODB.Recordset
rs.Open "select * from myTestTable", mDBConnection, adOpenDynamic, adLockOptimistic

adOpenDynamic 将允许向前/向后读取以获取您的记录数。

【讨论】:

我试过了,但是当我运行 rs.open 时出现错误:“发生错误。[,,,,,,]” 发生的错误是我在评论中提到的错误。当我越过 rs.open 时,它说“发生错误。[,,,,,,]”这不是很详细!!!!【参考方案8】:

如果仍然返回 -1,请尝试使用以下代码

Set Conn = createobject("ADODB.connection")
Set Rs = createobject("ADODB.recordset")
Conn.Open "DSN=DSN_QTP" 
'Rs.Open "Select * From orders",Conn,adOpenDynamic,adLockBatchOptimistic
Rs.Open "Select * from [QTP-Table]",Conn,1 'Use either 1 or 3
'I tried using adopendynamic but it still returned -1. Using 1 it gave me correct count.       'Though I am using this code in QTP (Vbscript) same should work for VB6 also.
msgbox Rs.RecordCount

【讨论】:

【参考方案9】:

你可以试试这样的..

Set rs = mCmd.Execute

rs.MoveFirst

Do Until rs.EOF = true

    Debug.Print rs.RecordCount  ' Always returns -1  !!
    Debug.Print rs.Fields(0)   ' returns correct data for first row, first col
    Debug.Print rs.Fields(1)   ' returns correct data for first row, 2nd col
    Debug.Print rs.Fields(2)   ' returns correct data for first row, 3rd col

   counter = counter + 1
   rs.MoveNext

Loop

【讨论】:

【参考方案10】:

以下代码可能对您有所帮助,

set conn = CreateObject("ADODB.Connection") 
conn.open "<connection string>" 
set rs = CreateObject("ADODB.Recordset") 
sql = "SELECT columns FROM table WHERE [...]" 
rs.open sql,conn,1,1 
if not rs.eof then 
    nr = rs.recordcount 
    response.write "There were " & nr & " matches." 
    ' ... process real results here ... 
else 
    response.write "No matches." 
end if 
rs.close: set rs = nothing 
conn.close: set conn = nothing 

【讨论】:

【参考方案11】:
Set cn = CreateObject("ADODB.Connection")

strVerb = "Provider=Microsoft.ACE.OLEDB.12.0;" & _
    "Data Source=C:\test.accdb"

tab1 = "tabelle1"

strSQL = "SELECT Count(*) FROM " & tab1

Debug.Print strSQL
         
cn.Open strVerb
Set rs = cn.Execute(strSQL)

Debug.Print rs.Fields(0)
    
rs.Close
Set rs = Nothing
cn.Close
Set cn = Nothing

【讨论】:

【参考方案12】:

您必须将 CONNECTION 设置为 aduseClient,没有记录集 并且小心只设置一个新的连接,如果你在你的项目中使用相同的连接,你可能会得到其他错误。

与 aduseclient 建立新的联系

Dim Sql As String
Dim CnCommand As New ADODB.Connection

On Error GoTo VerError:
Dim Comando As ADODB.Command
Set Comando = New ADODB.Command
CnCommand.ConnectionString = Cn.ConnectionString 'your exist connection in application
CnCommand.Open
CnCommand.CursorLocation = adUseClient
Set Comando.ActiveConnection = CnCommand

'Comando.ActiveConnection.CursorLocation = adUseClient
    
    Comando.Parameters.Append Comando.CreateParameter("@Usuario", adInteger, adParamInput, , V_General.Usuario.Codigo)
    
    Comando.CommandType = adCmdStoredProc
    
    Comando.CommandText = "SP_Contratac"
    Dim Rs As Recordset
    Set Rs = New ADODB.Recordset
    Set Rs = Comando.Execute()

【讨论】:

【参考方案13】:

以下代码准确返回记录计数...

Public Sub test()
    Dim cn As New ADODB.Connection()
    Dim sPath As String = Application.ExecutablePath
    sPath = System.IO.Path.GetDirectoryName(sPath)

    If sPath.EndsWith("\bin") Then
        sPath = sPath.Substring(0, Len(sPath) - 4)
    End If

    Dim DbConnectionString As String
    DbConnectionString = "provider=microsoft.jet.oledb.4.0;data source=" & sPath & "\students.mdb"

    cn.ConnectionString = DbConnectionString
    cn.Open()

    Dim rs As New ADODB.Recordset()
    rs.CursorLocation = ADODB.CursorLocationEnum.adUseClient
    rs.CursorType = ADODB.CursorTypeEnum.adOpenStatic
    rs.LockType = ADODB.LockTypeEnum.adLockBatchOptimistic
    rs.Open("select * from students", cn)
    MsgBox(rs.RecordCount)

    rs.ActiveConnection = Nothing
    cn.Close()
End Sub

【讨论】:

这使用 Access 数据库,而不是 SDF 数据库。

以上是关于VB6 ADODB.Recordset RecordCount 属性总是返回 -1的主要内容,如果未能解决你的问题,请参考以下文章

ADO Recordset 对象

ADO Recordset 对象

VBA 将整个 ADODB.Recordset 插入表中

Excel 单元格到 ADODB.Recordset

由于空格,ADODB.Recordset 到 SQL Server 查询失败

如何从此 ADODB.Recordset 中获取插入 ID?