Набор записей ADO теряет свои данные при последовательной передаче в несколько функций (Access VBA) - PullRequest
1 голос
/ 07 ноября 2011

У меня есть функция, которая возвращает набор записей ADO, который, в свою очередь, используется для подачи последующих функций. Первый раз, когда он передается одной из этих функций, он работает нормально; но в следующей функции набор записей находится в EOF. Я предполагал, что мой набор записей был передан By Ref, поэтому попытался использовать MoveFirst: это дает мне ошибку, потому что тип курсора по умолчанию установлен только для пересылки.

Я попробовал следующее:

  • Установите для этого параметра значение By Val; это не имело никакого эффекта.
  • Создала копию набора записей и использовала оригинал в первой функции и копию во второй; все та же проблема (во-вторых, говорит EOF, что означает, что он пуст, а не в EOF; я не могу представить, что два набора записей связаны каким-либо образом, но, возможно,).
  • Изменил код моей БД на использование другого типа курсора (adOpenStatic): Это на самом деле было бы более правильным для моего приложения, но оно дало очень странные результаты. А именно, в запросе, который работал нормально до, после изменения, первое поле не возвращалось! Это очень важно, поэтому я не мог продолжать идти по этому маршруту.

Есть идеи?


Функция запроса к основной БД: GetData. Принимает SQL и список varchar параметров (если есть) и возвращает набор записей. Он ссылается на dbOpen, который просто открывает соединение с предоставленными учетными данными.

Private Function GetData(ODBC As DBConnection, ByVal QuerySQL As String, Optional Parameters As Collection) As ADODB.Recordset
    Dim DB As ADODB.Connection
    Dim Query As ADODB.Command
    Dim Parameter As ADODB.Parameter

    Set DB = New ADODB.Connection

    If dbOpen(DB, ODBC) Then
        Set Query = New ADODB.Command
        Query.ActiveConnection = DB
        Query.CommandText = QuerySQL

        If Not Parameters Is Nothing Then
            For Each param In Parameters
                Set Parameter = Query.CreateParameter(, adVarChar, adParamInput, Len(param), param)
                Query.Parameters.Append Parameter
            Next
            Set Parameter = Nothing
        End If

        Set GetData = Query.Execute

        ' Uncommenting this seems to reset the data in GetData...
        ' A bit of a memory leak, but we assume VBA will take care of it :P
        'dbClose DB
    Else
        MsgBox "Cannot connect to the database.", vbExclamation
        Set GetData = Nothing
    End If
End Function

Затем я делаю что-то вроде этого:

Dim myRecords as ADODB.Recordset

' For the sake of argument, we assume this returns a nontrivial recordset
Set myRecords = GetData(someDSN, someSQL, someParameters)

Debug.Print myRecords.EOF ' Returns False

ID = writeHeader(myRecords)

Debug.Print myRecords.EOF ' Returns True

writeData ID, myRecords   ' Breaks because at EOF

Функция writeHeader будет проходить каждую запись в наборе записей, используя MoveNext. Однако, если я передам myRecords по значению или как копию, мы все равно получим проблему с EOF. Если я добавлю MoveFirst в конце кода итерации записи в writeHeader, он будет жаловаться, что я не могу перейти к началу такого набора записей. Если я изменю свою функцию GetData, чтобы Set GetData = Query.Execute был изменен на:

Set GetData = New ADODB.Recordset

GetData.CursorType = adOpenStatic
GetData.Open Query

Затем, когда в моем коде выполняется запрос, который не изменился, первое поле не является частью набора записей (!?). Скажем, например, myRecords!ID - это первое поле: если на него ссылаются, я получу предупреждение о том, что указанный элемент не является членом записей (и также не является перечисляемым элементом; поэтому myRecords.Fields(1) просто возвращает следующее поле в запросе).

1 Ответ

1 голос
/ 08 ноября 2011

С помощью полезного совета от @TimWilliams я решил эту проблему, изменив мою функцию GetData на следующую:

Private Function GetData(ODBC As DBConnection, ByVal QuerySQL As String, Optional Parameters As Collection) As ADODB.Recordset
    Dim DB As ADODB.Connection
    Dim Query As ADODB.Command
    Dim Parameter As ADODB.Parameter
    Dim Output As ADODB.Recordset

    Set DB = New ADODB.Connection

    If dbOpen(DB, ODBC) Then
        Set Query = New ADODB.Command
        Query.ActiveConnection = DB
        Query.CommandText = QuerySQL

        If Not Parameters Is Nothing Then
            For Each param In Parameters
                Set Parameter = Query.CreateParameter(, adVarChar, adParamInput, Len(param), param)
                Query.Parameters.Append Parameter
            Next
            Set Parameter = Nothing
        End If

        Set Output = New ADODB.Recordset
        Output.CursorType = adOpenStatic
        Output.CursorLocation = adUseClient
        Output.Open Query
    Else
        MsgBox "Cannot connect to the database.", vbExclamation
        Set Output = Nothing
    End If

    Set GetData = Output
End Function

Затем, перед курсором через набор записей, я использую MoveFirst.

...