This is the original code for a subform that is unbound and copied into the report module. I use it in an ADP attached to SQL Server.
I have to set NoOfLines because I can not add rows in a subform but you will no doubt be able to adapt it for your report detail by only adding each detail row as needed.
The original "virtual" concept was not mine but was posted in dbForums using specific text to populate the recordset (the author's comments were "Of course, I can't think of any particular use for this, but someone else may be able to."- if I knew who he/she was I would give them 10 stars), but I experimented with populating with live data and so far have found no issues. In the form, I then use SQL INSERTS,UPDATES and DELETES to manipulate the database.
Option Compare Database
Option Explicit
Dim rstf As Recordset
Dim rstd As Recordset
Private Const NoOfLines = 20
Private Sub Report_Open(Cancel As Integer)
On Error GoTo Errorhandler
Dim fld As Field
Dim strCriteria As String
Dim strFieldName As String
Dim intNameID As Integer
Dim x As Integer
Set rstf = New ADODB.Recordset
Set rstd = New ADODB.Recordset
'Create the virtual recordset
With rstf
.CursorLocation = adUseClient
.CursorType = adOpenKeyset
.LockType = adLockOptimistic
.Fields.Append "LineNo", adSmallInt
.Fields.Append "NameLocationID", adInteger, , adFldMayBeNull
.Fields.Append "NameID", adInteger, , adFldMayBeNull
.Fields.Append "DeliveryName", adVarChar, 50
' etc, etc
.Open
End With
'Preload the number of maximum record lines for the virtual recordset
With rstf
For x = 1 To NoOfLines
.AddNew
.Collect(0) = x
.Update
Next x
'Move the cursor position back to the first line
.MoveFirst
End With
'Load the real data into the virtual recordset
'intNameID = Nz(Me.Parent.OpenArgs
intNameID = 4
If intNameID Then
strCriteria = "SELECT * FROM tblNameLocations " _
& "WHERE NameID = " & intNameID & " " _
& "ORDER BY DeliveryName;"
rstd.Open strCriteria, CurrentProject.Connection, adOpenKeyset, adLockPessimistic
Do Until rstd.EOF
For Each fld In rstd.Fields
strFieldName = rstd(fld.Name).Name
rstf(strFieldName) = Nz(rstd(strFieldName))
Next fld
rstd.MoveNext
rstf.MoveNext
Loop
rstd.Close
End If
'Presumably here you would manipulate your recordset before binding to the report
Set Me.Recordset = rstf
Exit Sub
Errorhandler:
If Err = 2465 Or Err = 3265 Then
Resume Next
Else
Call Error_Display_Vars(Err, Application.CurrentObjectName)
End If
End Sub
Error_Display_Vars is a subroutine that displays and records in a table any user errors. Errors 2465 and 3265 trap for any fields brought over from the table that do not exist in my form/report so I can bring over only part of the table fields. Using a view as the table data should also work.
In the form (and also the report) I use the same field names from the table as the ControlSource and Name properties of the control so I do not have to type it all in manually hence the "For Each fld" code loop.
I would be very interested if it is successful in a report also, because I have never thought to use it that way and it could change a 2-pass report into a single pass report.