Свойство VB6 ADODB.Recordset RecordCount всегда возвращает -1

Я пытаюсь заставить старый код 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

Любой совет будет принят с благодарностью.


person Belliez    schedule 17.02.2010    source источник


Ответы (11)


На самом деле 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
person Kangkan    schedule 18.02.2010
comment
Хотя CursorLocation определяет поведение, оно в равной степени зависит от используемого вами драйвера. На самом деле rs.CursorLocation = adUseClient позволяет использовать курсоры драйвера. См. документацию используемого вами драйвера (Microsoft.SQLSERVER.CE.OLEDB.3.5) для получения информации о возможностях его курсора. Драйвер CE может не предоставить его. В этом случае вы можете искать обновленный драйвер. - person Kangkan; 19.02.2010
comment
Можете ли вы также установить свойство CursorLocation объекта соединения? - person Kangkan; 19.02.2010

Это результат типа курсора, используемого для доступа к данным, в этом посте рассматривается проблема и возможные исправления.

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

ИЗМЕНИТЬ

Прошу прощения, что не был более внимателен к тому, что вы имели дело с Компактом. С Compact ситуация аналогична той, на которую я ссылался, поскольку по умолчанию используются курсоры только вперед (которые не поддерживают подсчет строк), но есть два других типа курсоров, доступных, как описано в ссылке ниже.

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

person cmsjr    schedule 17.02.2010
comment
попробовал оба метода, и оба не смогли выполнить select * from myTestTable. Кстати, если я открываю sdf через Sql Server Management Studio 2008, sql работает и возвращает 11 строк. - person Belliez; 18.02.2010

Проверить свойство набора записей

Ниже приведен результат, который значение RecordCount возвращает код com.status.live.

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

Вот решение для вас, которое я использовал

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
person Syagin Cdit    schedule 15.12.2012

По памяти при работе с VB6/ADO давным-давно поле .RecordCount не возвращает значимых данных, пока вы не перейдете в конец набора записей.

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

Хотя при этом вам нужно убедиться, что у вас есть соответствующий тип курсора (т.е. не только вперед).

Единственное другое решение, которое я могу придумать, - это сделать отдельный SELECT COUNT(*) FROM myTestTable и т. д., но это имеет проблемы с изменением данных между этим вызовом и тем, который фактически возвращает строки.

person Gareth Wilson    schedule 18.02.2010

В Compact атрибут курсора по умолчанию — adOpenForwardOnly для повышения производительности. Таким образом, RecordCount возвращается как «-1», что означает, что он недоступен, а не пуст. Это сделано намеренно, потому что количество записей в динамическом курсоре может измениться, что может привести к пингу между клиентским сервером и обратно для поддержания точности. Однако, если количество записей жизненно важно, попробуйте настроить его на использование adOpenKeyset или adOpenStatic с курсором на стороне сервера.

person jasonk    schedule 19.02.2010

Попробуйте использовать следующий код, если он все еще возвращает -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
person Shailendra Sah    schedule 15.12.2013

Вы можете попробовать что-то вроде этого ..

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
person Kentot    schedule 20.12.2013

Замените Set rs = mCmd.Execute на:

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

adOpenDynamic позволит читать вперед/назад, чтобы получить количество записей.

person C-Pound Guru    schedule 17.02.2010
comment
Я пробовал это, но получаю сообщение об ошибке при запуске rs.open: Errors Occurred. [,,,,,,] - person Belliez; 18.02.2010
comment
произошла ошибка, которую я упомянул в своем комментарии. Когда я переступил через rs.open, он сказал, что произошли ошибки. [,,,,,,] что не очень подробно!!!! - person Belliez; 18.02.2010

Ниже код может помочь вам,

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 
person Ashfak Balooch    schedule 14.02.2011

Следующий код точно возвращает количество записей...

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
person ELANGOVAN    schedule 23.02.2010
comment
здесь используется база данных Access, а не база данных SDF. - person Belliez; 01.03.2010