Microsoft KB Archive/247868
Article ID: 247868
Article Last Modified on 7/2/2004
- Microsoft ActiveX Data Objects 2.1
- Microsoft ActiveX Data Objects 2.1 Service Pack 1
- Microsoft ActiveX Data Objects 2.1 Service Pack 2
- Microsoft ActiveX Data Objects 2.5
- Microsoft ActiveX Data Objects 2.6
- Microsoft ActiveX Data Objects 2.7
This article was previously published under Q247868
Some corporate policies allow read-only access to database tables with all updates being performed through stored procedures. If you want to bind a data control, such as the Microsoft Data Grid or List View control, to an ADO recordset, this can pose a problem keeping the recordset in sync with the data if you can allow adding, deleting, and modifying records but you cannot edit it directly through the recordset.
If you want to keep a recordset in sync with the server but you cannot add records through the hierarchical recordset, there are a number of workarounds:
- You can requery the recordset. This has the disadvantage of poor performance.
- You can disconnect the recordset and perform additions and other modifications in parallel with stored procedures. The problem here is that certain fields are read-only, such as Identity and TimeStamp, and you cannot set their value. This becomes problematic if the Identity column is supplied to the stored procedures to identify the record to be updated, or if the TimeStamp column is passed to the stored procedure to determine if someone else has edited the record in the meantime. There are a number of workarounds:
- You can copy the data to a local database, such as a Jet MDB, and use datatypes that do not make the field read-only. You can then update the recordset in parallel to using stored procedures and keep the data in sync.
- You can manufacture a recordset based on the original and copy the data into it. The fields are all updatable and you can update the recordset in parallel to using stored procedures.
This article provides sample code for the second workaround. It is generic enough to work with any non-hierarchical recordset (Chapter fields are not copied). If you need to use hierarchical recordsets, please refer to the following Microsoft Knowledge Base article:
241202 How To Produce a Manufactured Hierarchical Recordset Base on an Existing Recordset
This article provides the following functions:
|MakeRS||Creates a closed, empty Recordset with fields with the same names and data types as the original. Chaptered fields are not copied.|
|OpenAndFillRS||Opens the destination Recordset and copies data from the (already open) source Recordset. Data in Chaptered fields are not copied.|
The sample application has the following steps:
- It opens a recordset.
- It calls MakeRS to create an equivalent recordset that is not based on any provider and hence does not have any read-only fields.
- It calls OpenAndFillRS to open the recordset and copy the data from the original recordset.
- It closes the original recordset.
- It binds the ADO Data Grid to the manufactured recordset.
NOTE: The code does not provide samples of updating the server table and making equivalent changes to the manufactured recordset. This is left as an exercise for the reader because the manufactured recordset is now in a state to make this possible.
- Open a new project in Microsoft Visual Basic 6.0. Form1 is created by default.
- From the Projects menu, choose Components, select the "Microsoft DataGrid Control 6.0 (OLEDB)" control, and place it on the form. Make it fairly large.
- From the Projects menu, choose References, select "Microsoft ActiveX Data Objects 2.1 Library."
Add the following code to the form module:
Option Explicit Private Sub Command1_Click() Dim cn As ADODB.Connection, rsSource As ADODB.Recordset, rsDest As ADODB.Recordset Set cn = New ADODB.Connection cn.Open "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=nwind.mdb" Set rsSource = cn.Execute("SELECT * FROM Customers") Set rsDest = MakeRS(rsSource) OpenAndFillRS rsSource, rsDest rsSource.Close cn.Close Set DataGrid1.DataSource = rsDest End Sub Function MakeRS(ByVal rsSource As ADODB.Recordset) As ADODB.Recordset Dim rsTemp As ADODB.Recordset, F As ADODB.Field Set rsTemp = New ADODB.Recordset For Each F In rsSource.Fields If F.Type <> adChapter Then rsTemp.Fields.Append F.Name, F.Type, F.DefinedSize, F.Attributes And adFldIsNullable With rsTemp(F.Name) .Precision = F.Precision .NumericScale = F.NumericScale End With End If Next F Set MakeRS = rsTemp End Function Sub OpenAndFillRS(ByVal rsSource As ADODB.Recordset, ByVal rsDest As ADODB.Recordset) Dim F As ADODB.Field If rsSource.State = adStateClosed Then Exit Sub<BR/> If rsSource.EOF And rsSource.BOF Then Exit Sub If rsSource.CursorType <> adOpenForwardOnly Then If Not rsSource.EOF And Not rsSource.BOF Then rsSource.MoveFirst End If End If rsDest.CursorLocation = adUseClient rsDest.Open Do While Not rsSource.EOF rsDest.AddNew For Each F In rsSource.Fields If F.Type <> adChapter Then rsDest(F.Name).Value = F.Value Next F rsDest.Update rsSource.MoveNext Loop End Sub
- Add a CommandButton, modify the connect string in the Command1_Click procedure, and run the project. The customer's data is displayed in the grid after you click the CommandButton.
For additional information, click the following article number to view the article in the Microsoft Knowledge Base:
305346 How To Copy DataRows Between DataTables by Using Visual Basic .NET
Keywords: kbhowto KB247868