Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Memory, Stand-Alone, Disconnected ADO Recordset

I'm running this code on my datasheet subform when my form loads and I'm not getting any error messages or code breaks. My debug.print shows that the Recordset rs is filled with 2131 records like it should be, but my form shows a single row with #Name? in every field. The control source properties on my controls most certainly do match the field names I have listed above. RS is a form level variable and I'm not closing it or setting it to nothing until the form closes.

Any idea what am I doing wrong?

Set rs = New ADODB.Recordset
rs.Fields.Append "TimesUsed", adInteger
rs.Fields.Append "strWorkType", adVarWChar, 150
rs.Fields.Append "DateLastUsed", adDate
rs.Fields.Append "SelectedYN", adBoolean
Set rs.ActiveConnection = Nothing
rs.CursorLocation = adUseClient
rs.LockType = adLockBatchOptimistic
rs.Open

Dim sSQL As String
sSQL = "MyComplicated SQL Statement Ommitted from this SO Question"

Dim r As DAO.Recordset
Set r = CurrentDb.OpenRecordset(sSQL, dbOpenDynaset, dbSeeChanges)
If Not (r.EOF And r.BOF) Then
    r.MoveFirst
    Dim fld
    Do Until r.EOF = True
        rs.AddNew
        For Each fld In r.Fields
            rs(fld.Name) = r(fld.Name).value
        Next
        rs.Update
        r.MoveNext
    Loop
End If
r.Close
Set r = Nothing
Debug.Print rs.RecordCount '2131 records
Set Me.Recordset = rs

OK, so I just read this on the MSDN site:

The recordset must contain one or more fields that are uniquely indexed, such as a table's primary key.

(Note: This information seems to be erroneous in this context.)

like image 886
HK1 Avatar asked May 05 '12 02:05

HK1


People also ask

What is a disconnected recordset?

Instead, the user can take advantage of the server's ability to create disconnected Recordsets. These are, as the name suggests, Recordsets that have been disconnected from the data source, thus allowing the user to work off-line and move freely between records.

How do I Disconnect a recordset from aduseclient?

To disconnect a Recordset, open it with a cursor location of adUseClient, and then set the ActiveConnection property equal to Nothing. (C++ users should set the ActiveConnection equal to NULL to disconnect.)

How to declare ADO constants in recordset?

Both these ADO constants must be declared before the Recordset is opened, either explicitly in the code module in question, or through the inclusion of the 'adovbs.inc' file.

Does the default form sorting work with ADO Records?

The default form sorting does not appear to work when you have your form bound to an ADO recordset. Also, for some reason I never could get this recordset to be editable/updateable which was a requirement for my needs (I was basically using it as a multi-check list).


3 Answers

is it possible to setup a primary key on a recordset that is only an in-memory object?

Yes, use adFldKeyColumn as the Attrib to the Append Method. Read about FieldAttributeEnum for more details.

If you already have a suitable unique field (or combination of fields) available from your SQL statement, use that. If not, create a long integer field and use it as a fake primary key field ... increment the value for each row you insert.

rs.Fields.Append "pkey", adInteger, , adFldKeyColumn

Also see if this article from Database Journal by Danny Lesandrini is helpful: Create In-Memory ADO Recordsets

like image 131
HansUp Avatar answered Oct 11 '22 15:10

HansUp


I found out that the only way I can make this work is to use LockType adLockPessimistic or adLockOptimisic. adLockReadOnly doesn't work for obvious reasons and for some reason adLockBatchOptimistic does not allow records to display in my form even though the recordset appears to be fully functional.

I also found out that you do not have to have a primary key defined for this type of disconnected Recordset to be bound to a form. I'm sure you won't be able to make any edits or updates to the recordset via the form but in my testing I found that I couldn't make any edits to this type of form/recordset anyway because I was getting Error 3270 (something to do with a missing property). That's really outside the scope of this question.

Here's the minimum amount of code needed to create a working in-memory recordset:

Dim rs As ADODB.Recordset 'Form Level variable

Private Sub Form_Load()
    Set rs = New ADODB.Recordset
    rs.Fields.Append "ID", adInteger
    'Set rs.ActiveConnection = Nothing 'Not Required
    'rs.CursorType = adOpenKeyset 'Not Required
    'rs.CursorLocation = adUseClient 'Not Required
    rs.LockType = adLockPessimistic 'May also use adLockOptimistic
    rs.Open

    Dim i as Integer

    For i = 1 To 10
        rs.AddNew
        rs("ID").Value = i
        rs.Update
    Next i

    Set Me.Recordset = rs
End Sub

It first appeared to me that binding a form (datasheet view in my case) to this type of disconnected recordset would be a good, simple solution for my particular needs. However, I ran into several problems. The default form sorting does not appear to work when you have your form bound to an ADO recordset. Also, for some reason I never could get this recordset to be editable/updateable which was a requirement for my needs (I was basically using it as a multi-check list). If you obtain the recordset from a table (even if it's an empty table) and then disconnect you can work around this problem. Apparently the table supplies some kind of structure or properties that I've failed to set in my code above, judging by the 3270 error message I get when I try to add/edit a record. And I haven't figured out what those properties are or how to set them.

In conclusion, I think I'll resort to using an Access "temp" table instead since it will be less complicated and not have the problems I've just listed above.

like image 42
HK1 Avatar answered Oct 11 '22 14:10

HK1


Note: I was able to get everything to work correctly along with inserting new records by using the example shown above at Create In-Memory ADO Recordsets Then changing the following to the forms code... 'Note: The trick was to use rstADO.MoveFirst & rstADO.MoveLast after the rstADO.Update

Option Compare Database
Dim rstADO As ADODB.Recordset
Dim lngRecordID As Long

Private Sub Form_BeforeInsert(Cancel As Integer)

    lngRecordID = lngRecordID + 1
    rstADO.AddNew
    rstADO("EmployeeID").value = lngRecordID
    rstADO.Update
    rstADO.MoveFirst
    rstADO.MoveLast

End Sub

Private Sub Form_Load()

    Dim fld As ADODB.Field

    Set rstADO = New ADODB.Recordset
    With rstADO
        .Fields.Append "EmployeeID", adInteger, , adFldKeyColumn
        .Fields.Append "FirstName", adVarChar, 10, adFldMayBeNull
        .Fields.Append "LastName", adVarChar, 20, adFldMayBeNull
        .Fields.Append "Email", adVarChar, 64, adFldMayBeNull
        .Fields.Append "Include", adInteger, , adFldMayBeNull
        .Fields.Append "Selected", adBoolean, , adFldMayBeNull

        .CursorType = adOpenKeyset
        .CursorLocation = adUseClient
        .LockType = adLockPessimistic
        .Open
    End With
    Set Me.Recordset = rstADO

End Sub

Private Sub Form_Unload(Cancel As Integer)

    Set rstADO = Nothing

End Sub
like image 41
John Reaume Avatar answered Oct 11 '22 14:10

John Reaume