DAO.Recordset based on DAO.QueryDef as source for Multiple Items form

mdlueck

Sr. Application Developer
Local time
Today, 05:22
Joined
Jun 23, 2011
Messages
2,633
A while ago we were having a discussion about having a ADO objects feed data into an Access Multiple Items form. Today I discovered one can do almost exactly the same with a DAO.Recordset based on DAO.QueryDef.

Link to our prior Access Continuous Form fed via ADO objects:

"Example of ADO objects being bound to a Continuous / Multiple Items type form"
http://www.access-programmers.co.uk/forums/showthread.php?t=258559&page=2#post1319473

So my working DAO.Recordset version:

To build the DAO.QueryDef object and store it to the FE DB:
Code:
Public Function dao_builddao() As Boolean

  Dim strSQL As String
  Dim daoDB As DAO.Database
  Dim daoQDF As DAO.QueryDef

  strSQL = "SELECT [t].[pid],[t].[quoteid],[t].[metflg],[t].[metid],[t].[mettitle],[t].[toolstatusid],[t].[tooltypetitle],[t].[partnumber],[t].[parttitle],[t].[partvendortitle],[t].[toolstatustitle],[t].[lttotal],[t].[toolduedate],[t].[besttoolcost],[t].[prodpartflg]" & vbCrLf & _
           "FROM [tblRptPartsToolCost] AS [t]" & vbCrLf & _
           "ORDER BY [t].[partnumber]"

  'Attach to the FE DB
  Set daoDB = CurrentDb()

  'Build the Query
  Set daoQDF = daoDB.CreateQueryDef("testdao")
  With daoQDF
    .SQL = strSQL
    .Close
  End With

  'Clean up the connection to the database
  Set daoQDF = Nothing
  Set daoDB = Nothing

  dao_builddao = True

End Function
Then the code for the form that is going to use the DAO.QueryDef object:
Code:
Option Compare Database
Option Explicit

  Dim daoDB As DAO.Database
  Dim daoRST As DAO.Recordset

Private Sub Form_Open(Cancel As Integer)

  'Attach to the FE DB
  Set daoDB = CurrentDb()

  'Execute the saved QueryDef
  Set daoRST = daoDB.OpenRecordset("testdao")

End Sub

Private Sub Form_Load()

  With Me
    .InsideHeight = 8400
    '.InsideWidth = 2200
    Set .Recordset = daoRST
  End With

  'Advance UI to the 7th record
  DoCmd.GoToRecord acDataForm, "PartsToolCost_DAO", acGoTo, 7

End Sub


Private Sub Form_Close()

  daoRST.Close
  Set daoRST = Nothing
  Set daoDB = Nothing

End Sub
So this success has me considering if I could swap out using FE Temp Tables to cache multiple records to be displayed in an Access Continuous Form, instead use a DAO.Recordset, but...

What about my use of FE Temp Tables where upon saving an edited record back to the BE DB, I select out of the BE DB that one updated record, refreshing the FE DB Temp Table, and then refresh the Access Form UI to display in the Mutiple Items grid that just updated record?

Is there a way I can do that same sort of thing retaining the rest of the unchanged rows already in the DAO.Recordset, delete by record ID the one being updated, and download a fresh copy of that updated record retaining the rest of the records already in the DAO.Recordset object?

I suppose I could do like my example code and define the "Dim daoRST As DAO.Recordset" object up at the form level so it would remain in-scope the entire time the particular form is open.

Is it possible to perform a delete by unique row ID within the populated DAO.Recordset, then select into the DAO.Recordset by unique row ID the record that was updated? Sort of using the DAO.Recordset as an in-memory table the Continuous Form gets bound to.

I am thankful,
 
Last edited:
Why are you using either of the code above?
Cant you just use an append query? No code needed.
 
Why are you using either of the code above?

This is prototyping / experimental code, which I am treating an Access table as if it were a SQL BE DB table.

In production use, yes I would be using a Pass-Through query to execute a Stored Procedure on the SQL BE DB, and and and... Keeping it very simplistic for my forum question.

The goal is to prototype using a DAO.Recordset to bind the Access form to, rather than a FE Temp Table. I believe I must use a bound form in some way/shape/form in order to use an Access Continuous Form to display more than one record.

Cant you just use an append query? No code needed.

I do not believe merely / solely an append query would be able to accomplish the task entirely... I believe an append query by itself would result in adding the updated state of the BE DB row which was edited while also leaving the row reflecting the prior-to-just-edited state.

And could I really use a DAO.Recordset as the Access Form Recordset without any code? I highly doubt. Please explain further.

I am thankful,
 
Last edited:
This is prototyping / experimental code, which I am treating an Access table as if it were a SQL BE DB table.

In production use, yes I would be using a Pass-Through query to execute a Stored Procedure on the SQL BE DB, and and and... Keeping it very simplistic for my forum question.

The goal is to prototype using a DAO.Recordset to bind the Access form to, rather than a FE Temp Table. I believe I must use a bound form in some way/shape/form in order to use an Access Continuous Form to display more than one record.

Maybe I'm missing the point here (it happens...) but...
A linked table (Access or SQL Server or Excel etc) or a SELECT query based on that can be used as the record source for a form.
If the table has more than 1 record, all record will be displayed at once if it is continuous or a datasheet.

I don't see why you need pass through queries, append queries or DAO.recordsets ...or anything else come to that
As the linked table is 'LIVE', the form will always show the latest data

No code needed .. except possibly a requery if the form is open whilst another user updates the data
 
I don't see why you need pass through queries

In order to invoke the Stored Procedure on the SQL BE DB.

As the linked table is 'LIVE', the form will always show the latest data

No code needed .. except possibly a requery if the form is open whilst another user updates the data

But I do not use Linked Tables at all. The SQL Stored Procedures on the SQL BE DB frequently join many tables within the BE DB into a concise single record set. Those are downloaded to the Access FE DB for display, and no long lasting links are kept alive to the SQL BE DB. "Connect / Do SQL Business / Disconnect" all very transactional and multi-user friendly.

Restating the original question:

Is it possible to perform a delete by unique row ID within the populated DAO.Recordset, then select into the DAO.Recordset by unique row ID the record that was updated? Sort of using the DAO.Recordset as an in-memory table the Continuous Form gets bound to.

I am thankful,
 
Michael

But I do not use Linked Tables at all. The SQL Stored Procedures on the SQL BE DB frequently join many tables within the BE DB into a concise single record set. Those are downloaded to the Access FE DB for display, and no long lasting links are kept alive to the SQL BE DB. "Connect / Do SQL Business / Disconnect" all very transactional and multi-user friendly.

Can you explain why you don't just use linked tables to connect to your BE?
Its the standard method of connecting to a BE & is certainly much simpler than what you are trying to do here.
You could then just use update queries as needed (or the SQL equivalent)
If you have a large number of records, this will also be far faster than using recordsets to update your data
 
A while ago we were having a discussion about having a ADO objects feed data into an Access Multiple Items form. Today I discovered one can do almost exactly the same with a DAO.Recordset based on DAO.QueryDef.
If you already got working solution with ADO, why do you want to throw that out and replace it with a DAO based solution that, due to missing features in DAO, will have some limitations?


Is it possible to perform a delete by unique row ID within the populated DAO.Recordset, then select into the DAO.Recordset by unique row ID the record that was updated? Sort of using the DAO.Recordset as an in-memory table the Continuous Form gets bound to.
No!
 
Well personally I think a bit of encouragement is in order! I like to see an exploration of other possibilities, you never know where it may lead.

Although I don't think you can have a persistent recordset in DAO you definitely can in ADO and I'm wondering if that might be a way of replacing MS Access Replication, which was quite a handy feature I believe...
 
Last edited:
Michael

Can you explain why you don't just use linked tables to connect to your BE?

1) Security risk of people tinkering opening the linked tables through the Access UI, changing things ad-hock.

2) Speed. Using exclusively Stored Procedures for SQL BE DB and disconnected recordsets in the Access FE DB delivers lighting fast performance.

Just the one downside is Access FE DB bloat... which I refresh the FE DB each time the application starts to address this point. Shared about my solution here:

FE AutoUpdate with RoboCopy / XCopy
http://www.access-programmers.co.uk/forums/showthread.php?p=1214733#post1214733


I am thankful,
 
If you already got working solution with ADO, why do you want to throw that out and replace it with a DAO based solution that, due to missing features in DAO, will have some limitations?

I have not rolled out a production application with the ADO solution... researching options.

For production Access Client/Server applications, those make use of Access FE temp tables records are downloaded into, the Access Continuous Forms are bound to via a Access FE QueryDef.

I am considering how to swap out for something in memory (Recordset be it DAO or ADO) to replace relying on a FE temp table.


Quote:
Originally Posted by mdlueck
Is it possible to perform a delete by unique row ID within the populated DAO.Recordset, then select into the DAO.Recordset by unique row ID the record that was updated? Sort of using the DAO.Recordset as an in-memory table the Continuous Form gets bound to.


Which part is "No!"

Obviously binding Access Continuous Forms to DAO/ADO.Recordset objects IS possible.

Looks like I would need to rely on cursor type methods of the Recordset objects to locate / update / change / delete records in it... looks like no SQL capabilities against Recordset objects.

If I define the Recordset object at Form level, it should remain in scope the entire time the form is open.

So, again, which part is "No!"?

I am thankful,
 
1) Security risk of people tinkering opening the linked tables through the Access UI, changing things ad-hock.

2) Speed. Using exclusively Stored Procedures for SQL BE DB and disconnected recordsets in the Access FE DB delivers lighting fast performance.

Just the one downside is Access FE DB bloat... which I refresh the FE DB each time the application starts to address this point. Shared about my solution here:

FE AutoUpdate with RoboCopy / XCopy
http://www.access-programmers.co.uk/forums/showthread.php?p=1214733#post1214733

1. If you deploy the FE as an ACCDE with both navigation pane and ribbon hidden there is virtually no chance of anyone tampering with linked tables. A determined hacker can break into any system, certainly including SQL Server.
What all developers try and prevent is someone accidentally or deliberately tinkering... BUT no system is foolproof.

2. I agree that stored procedures can be very fast and, in situations where it makes a dramatic difference, I also use them. However, I certainly wouldn't do so for every process.

3. Glad you raised DB bloat as I would have done so myself. Another issue caused by repeatedly creating new objects and deleting them is that the FE can become unstable and lead to crashes. Decompiling will normally handle that but I would rather avoid a process which may trigger either bloat or instability.

Clearly we aren't going to agree.
This discussion seems similar in some ways to a recent thread about unbound forms https://access-programmers.co.uk/forums/showthread.php?t=299757
You have a method that works for you but it isn't an approach that many of us would want to employ.

Best of luck
 
So, again, which part is "No!"?
All of them!


Yes, it is possible to bind a form to a DAO.Recordset, obviously. But that's where it ends.


You can not use "cursor type methods of the Recordset objects to locate / update / change / delete records" in the DAO recordset on its own. All those changes will be immediately send to the underlying table once you update the (single) row in the recordset. This is pretty inconvenient already. But it gets worse in combination with a Pass-Through-Query. These are not updatable. So no editing in that recordset at all.
 
All of them!

Yes, it is possible to bind a form to a DAO.Recordset, obviously. But that's where it ends.

You can not use "cursor type methods of the Recordset objects to locate / update / change / delete records" in the DAO recordset on its own. All those changes will be immediately send to the underlying table once you update the (single) row in the recordset.

So my Client/Server design is to SELECT to the FE DB to display in a totally disconnected FE interface.

There is a Requery button on each Multiple Items form to refresh the data completely by rerunning the Stored Procedure, purge and refresh the FE Temp Table.

So when Updates are made to the BE DB, then my technique is to query again from the SQL BE DB just the one record by ID that the FE knows it updated.

I do not want long hanging sessions open to the BE DB.


But it gets worse in combination with a Pass-Through-Query. These are not updatable. So no editing in that recordset at all.

Correct, they are not updatable since the Stored Procedure that populated the FE DB is a SELECT Stored Procedure.

I can get the BE DB updated... I just need to be able to retain the rest of the records of the FE DB Recordset object, update the one record the FE knows it just successfully edited.

I will tinker a bit further based on the Microsoft post I found, referenced above... but first need to see if I can flip the populated Recordset to being disconnected, and reflect an edit to it.... in other words downloading just the one changed record while retaining the rest of the records.

I am thankful,
 
1. If you deploy the FE as an ACCDE with both navigation pane and ribbon hidden there is virtually no chance of anyone tampering with linked tables. A determined hacker can break into any system, certainly including SQL Server.
What all developers try and prevent is someone accidentally or deliberately tinkering... BUT no system is foolproof.

I prefer to deploy to clients sites in raw ACCDB... zero "Mac Truck" issue.

So automatically close the navigation pane and ribbons, but do not more extensively prevent clients from re-opening them if they feel the need to.

2. I agree that stored procedures can be very fast and, in situations where it makes a dramatic difference, I also use them. However, I certainly wouldn't do so for every process.

For consistency I Stored Proceduralized all interaction to the SQL BE DB.


3. Glad you raised DB bloat as I would have done so myself. Another issue caused by repeatedly creating new objects and deleting them is that the FE can become unstable and lead to crashes. Decompiling will normally handle that but I would rather avoid a process which may trigger either bloat or instability.

I go through my Compact / Decompile process when I promote up a new version of the application. Workstations refresh the FE DB next time they start, and always provide a clean copy of the master FE DB when restarting via the Program icon. Again... clients are free to open Access directly, open the FE DB from recent DB's used, and that way bypass the Software Distribution which is invoked via the dedicated program icon.

This discussion seems similar in some ways to a recent thread about unbound forms https://access-programmers.co.uk/forums/showthread.php?t=299757

The nasty bit seems to come in with Multiple Items forms. Barring that, unbound forms are easy. But with stepping into Multiple Items / Continuous Forms, then some sort of table object is needed to keep track of the multiple records.

I am thankful,
 
... but first need to see if I can flip the populated Recordset to being disconnected, and reflect an edit to it.... in other words downloading just the one changed record while retaining the rest of the records.
I think, I mentioned it before... It is not possible to disconnect DAO recordsets.



ADO recordsets on the other hand have most of the functionality you want built-in. What's missing though, is the possibility to use custom UPDATE/INSERT/DELETE commands. So, you will not be able to use your stored procedures for these operations.


Now, you have got two options.

1.) Keep your existing infrastructure of local temp tables and sync them to the SQL BE. This may have disadvantages regarding concurrency issues with multiple users. With this approach you (your code) is responsible for handling these issues, while otherwise most potential issues will be automatically handled (more or less well) by the data access library (DAO or ADO).


2.) Switch over to ADO data access and use disconnected recordsets. That way you will get most of the functionality you ask for out of the box. But you'll find it to be difficult (maybe impossible) to implement the missing parts.


Replacing an existing system with one that is less work to implement but will have some limitations when finished seems not to be a good deal for me. - The choice is yours...
 
I think, I mentioned it before... It is not possible to disconnect DAO recordsets.

Ah, I must have missed that point.

I was concluding myself last evening that I did not see any advantages to using DAO objects over ADO... in fact, more challenging.

So I will go off seeking the correct way to make manual edits to the ADO.Recordset to update the one record which is recently edited.

The form's Requery button takes care of when users want to refresh then entire Multiple Items form... suspecting other users have changed other records in their same view.

I am thankful,
 

Users who are viewing this thread

Back
Top Bottom