Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"Operation not supported in transactions" While Copy/Paste Records in Access

When copy / pasting cells from Excel into an Access Subform, when no parent record has been created, will result in an error - as expected.

The problem, is that after this error occurs access gets locked in a state where all subsequent data that is entered results in an Operation not supported in transactions error. When you open the table, you can see that the newly added data is not yet in the table - so it appears as if Access is in fact engaged in some sort of transaction.

I have tried hitting 'Save' .. 'Refresh' .. and even adding an AfterInsert event to force a commitTrans() but have had no luck - and Access claims there is no transaction underway

There is no error if the records are entered manually. The problem only seems to occur when pasting records. I'm guessing that Access is creating a transaction to handle the multiple record operations and is not properly recovering from the error.

I can remove the 'Required' flag and it will work - but then you have orphan records. I was thinking that perhaps an After Insert Data Macro could be used to add a new Batch with a default batch Name, and auto-fill the new BatchID into the Items table. I am not certain how that would be done however.

I did try to remove the 'Required' flag and trap for the error using a Before Change Data Macro - but while it cut down on the errors - it still produced the same Operation not supported in transactions error.

I have looked up the error on the Microsoft Knowledgebase, but did not find anything specific to my circumstances. I searched stackoverflow for the error message and found nothing.

I created a new database and was able to replicate the issue.

Steps to Replicate

Set up the Database

  1. Create a new ACCDB database in Access 2010
  2. Create a Table called 'Batches', with the following fields:
    • BatchID (AutoNumber) (Primary Key)
    • BatchName (Text)
  3. Create a Table called 'Items', with the following fields:
    • RecordID (AutoNumber) (Primary Key)
    • BatchID (Long Integer)
      • Set Required attribute to True
    • Data - Text
  4. Create a Relationship, linking Batches.BatchID to Items.BatchID
    • Include all Records from Batches, and matching records from Items
    • Enforce Referential Integrity
    • Cascade Updates / Deletes
  5. Create a Form called 'Form'
    • Set the Recordsource to Batches
    • Add in the BatchID and Batch name Textboxes
    • Add in a SubForm/SubReport Control
      • Set Source Object to "Table.Items"
      • Set Link Master Fields to "BatchID"
      • Set Link Child Fields to "BatchID"
      • Set "Filter On Empty Master" = Yes
  6. Create sample data (Using the Form)
    • Create a New Record in Batches.
      • Set BatchName = "Test"
    • Create a New Record in Items.
      • Reference the Batch Record.
      • Set Data = "Test"

As you can see, by hand this works fine.

Copy and Paste Data From Excel

  1. In Excel
    • From A1-A10 enter one letter per cell running down: A,B,C,D,E,F,G,H,I,J
    • Highlight the cells A1-A10
    • Copy (Control+C)
  2. In Access, using the Form:
    • Add a New Batch Record. It should say "(New)" in BatchID TextBox
    • Do NOT enter a Batch Name
    • In the Sub-Form, click the record selector (*) for the new record to select the entire row. Type Control+V to paste.
    • Click OK for "You must enter a value in the 'Data.BatchID' field. error
      • This error may repeat. Keep Clicking OK
      • If it asks "Do you want to suppress further error messages..." answer Yes
    • Click OK for the "Records that Microsoft Access was unable to paste have been inserted into a new table called 'Paste Errors.' notification
    • Fill in the Batch Name Textbox with "TestName"
    • Try to gracefully recover. Hit Escape. Change the Record.

At this point - you should see the BatchID entered, the Batch Name, and the New Data. Everything appears to be working as expected. If you try to refresh or navigate to another batch record - you will get the error Operation not supported in transactions. Access will continue to display this error message until we close and reopen the form. The data you pasted will not have made it into the database.

Normally someone with a bit of tech savvy will realize something isn't going well and close out of the database and re-open ... but unfortunately I have users that play "whack-a-mole" with any popup boxes and then try to continue on - so I'd like to make things as bulletproof as possible.

Desired Solution

I'd like a workaround to the problem, that won't eventually lead to other quirks with access, duplicate values, etc.

In my own experience, using VBA to 'fix-up' keys isn't reliable. Data macros seem to be a lot more reliable - but they can be tricky to set up - they aren't very mainstream yet (I'd say there should be a ms-access-data-macros tag on stackoverflow but there isn't yet)

like image 229
DHW Avatar asked Oct 21 '22 21:10

DHW


2 Answers

Suggested workaround:

In the [Batches] table, set the Required property of the [BatchName] field to Yes.

Change the Tab Stop property of the [BatchID] text box to "No". That will give the [BatchName] text box the default focus when the form opens.

Have the On Current event of the form give the [BatchName] text box the focus for new records (IsNull(Me.BatchID) = True).

Make the form dirty when the [BatchName] text box loses focus.

Option Compare Database
Option Explicit

Dim DeletePending As Boolean

Private Sub Form_Load()
    DeletePending = False
    Me.ItemSubForm.Enabled = False  ' Disable Subform by default
End Sub

Private Sub Form_Current()
    If IsNull(Me.BatchID) Then
        Me.BatchName.SetFocus
        ' Disable Subform if BatchID is NULL
        Me.ItemSubForm.Enabled = False
    Else
        ' Enable SubForm Otherwise
        Me.ItemSubForm.Enabled = False 
    End If
End Sub

Private Sub Form_BeforeDelConfirm(Cancel As Integer, Response As Integer)
    DeletePending = True
End Sub

Private Sub Form_AfterDelConfirm(Status As Integer)
    DeletePending = False
End Sub

Private Sub BatchName_LostFocus()
    If IsNull(Me.BatchID) And Not DeletePending Then
        Me.Dirty = True
    End If
End Sub

When the user clicks on the subform (and off the [BatchName] text box) they make the form dirty and BatchID gets a value. Then they can paste and they don't get the "You must enter a value..." message for [BatchID]. If they haven't entered a [BatchName] value they now get prompted for it (because it is now Required), but at least they can gracefully recover from that.

Updated 2013-11-09 18:40 UTC:

In playing around with this a bit more I discovered two quirks:

  1. If you deleted the last parent record Access would do it and then immediately create another new one in its place.

  2. If you navigated into the "new" parent record and then immediately backed out (e.g., via the PageDown and PageUp keys) Access would create a new record and then leave you on that record with the form dirty. Hitting Esc and then moving off the "new" record worked, and it didn't cause any errors, but it certainly could be confusing to the user.

I have updated the answer to try and address these issues. I added a bit more VBA code to track "DeletePending" status. I also added the requirement that [BatchName] be set to Required = Yes in the [Batches] table. The latter makes it slightly more intuitive (albeit slightly more annoying) if the user move into the "new" record and then immediately moves back out again.

like image 113
Gord Thompson Avatar answered Oct 24 '22 00:10

Gord Thompson


I struggled with this for a long until I finally understood what is happening to cause this error. It would take an article of considerable length to go into the details rather than a blog response to explain it all. If anyone is interested they can leave a contact method and I will contact them and explain it in detail. However, for those who want to figure this out, I can save you a lot of time by giving you the idea behind the issue: When you are performing a data transaction in a bound sub-form, you cannot reference other objects. The internal code of the transaction process does not allow this. For example, if you have code in the Form_BeforeUpdate event that attempts to open another form while in the midst of a sub-form data transaction, you will get error 3246. You can have code that creates variables, set values, references the sub-form controls, etc. but you cannot go out to another object. This makes sense if you think about it. Who knows what the user or code might do once it gets itself into another form or object. It may never come back or get involved in other errors that leave the transaction hanging. That's why the transaction must complete first. This means that you must trap and dismiss error 2115 that is caused when a user tries to click on an area outside the sub-form while in the midst of a transaction. This usually occurs during large copy and paste where the user becomes inpatient or starts to proceed to another record while still in the midst of the sub-form transaction.

like image 38
Stev3e Avatar answered Oct 23 '22 23:10

Stev3e