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

14

我正在尝试让一些旧的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
任何建议都非常受欢迎。
13个回答

9

实际上,在这种情况下,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驱动程序可能不提供它。在这种情况下,您可以寻找升级的驱动程序。 - Kangkan
你也可以设置连接对象的CursorLocation属性吗? - Kangkan
将set to aduseserver的连接设置为连接,而不是记录集。使用新/其他连接。 - R.Alonso

3
这是由于用于访问数据的光标类型导致的结果,本文介绍了这个问题以及可能的解决方法。

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

编辑

对于我没有更加关注您正在处理Compact的事实,我深表歉意。与我所提到的情况类似,Compact默认使用仅向前的游标(不支持行计数),但是在下面链接中有两种其他游标类型可用。

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


尝试了两种方法,都无法执行“select * from myTestTable”。顺便说一下,如果我通过Sql Server Management Studio 2008打开sdf,则可以正常工作并返回11行。 - Belliez

3

根据我之前使用VB6/ADO的经验,只有当你移动到记录集的结尾时,.RecordCount字段才会返回有意义的数据。

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

尽管如此,您需要确保拥有适当的光标类型(即,不是向前唯读)。
我能想到的唯一其他解决方案是执行单独的 SELECT COUNT(*) FROM myTestTable,等等,但是这会导致在该调用与实际返回行之间数据发生更改的问题。

2

使用Compact时,默认的光标属性是adOpenForwardOnly,这可以提高性能。因此,RecordCount返回“-1”,表示它不可用,而不是空白。这是有设计意图的,因为动态光标中记录数可能会发生变化,从而在客户端和服务器之间来回进行通信以保持准确性。但是,如果记录计数非常重要,请尝试将其设置为使用服务器端光标的adOpenKeyset或adOpenStatic。


2
您可以尝试像这样做...
(注:保留HTML标签,无需翻译解释)
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

2

检查记录集属性

以下是由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      |
+------------------+-------------------+-------------+---------------+--------------+

2

这是我使用过的一个解决方案。

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

1

Set rs = mCmd.Execute 替换为:

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

adOpenDynamic将允许通过前向/后向读取来获取记录数。


我尝试了这个,但是当我运行rs.open时出现错误:"发生错误。[,,,,,,]" - Belliez
发生的错误是我在评论中提到的那个。当我跨越rs.open时,它显示“发生错误。[,,,,,,]”,这并不是非常详细的说明!!! - Belliez

1
如果仍然返回-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

0

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

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 

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接