3
votes

I am doing some maintenance work on a linked-table application in Microsoft Access 2010 and experiencing this little gem of a problem. The application is linked to a SQL Server 2008 database. The application has a main form that allows a user to choose a combination of park code and resource and pops up an edit form for the details of that particular combination. If that combo doesn't exist in the database, the application inserts a new record in, but the issue is that 2 records get inserted.

Here's the seat of the problem code, it gets called when I need to insert a new record in a details popup form:

Private Sub New_Rec(unit_code As String, resource As String, sql As String)

   DoCmd.RunSQL ("INSERT INTO PARK_RESOURCES (unit_code, resource, sensitivity) VALUES " _
    & "('" & unit_code & "','" & resource & "','public')")

   'Force an explicit save
   'http://www.pcreview.co.uk/forums/update-cancelupdate-without-addnew-edit-t1150554.html
   If Me.Dirty Then
      Me.Dirty = False
   End If

   Me.RecordSource = sql
End Sub

Creating a "new" record results in 2 records getting inserted into the Recordset. It doesn't seem to matter if I move the explicit save code before or after setting the RecordSource. In either order (and stopping after either) produces 2 new records inserted in the database (verified by querying in SSMS).

When I set the RecordSource property and step through the code, the event chain looks like: Me.RecordSource = sql --> Form_BeforeUpdate() --> Form_AfterUpdate() --> Form_After_Insert() --> Form_Current(). The duplicate is not present at the close of BeforeUpdate, but by the time I get to AfterUpdate, the duplicate has already been inserted. What happens between BeforeUpdate and AfterUpdate that causes this to happen?

According to MSDN, the order is: BeforeInsert → BeforeUpdate → AfterUpdate → AfterInsert. They also state that setting the value of a control through Visual Basic doesn't trigger these events. But when I update the RecordSource in code, the last 3 events certainly fire; BeforeInsert is the only one that a step-through doesn't stop on.

As per Daniel Cook's request, here is the calling code.

Private Sub Form_Load()
   On Error GoTo Err_Form_Load

   Me.KeyPreview = True
   If Not IsNull(Me.OpenArgs) Then
      ProcessOpenArgs (Me.OpenArgs)
      Me.lblHeader.Caption = Me.unit_code & ": Resource - " & Me.resource
   Else
      Me.lblHeader.Caption = "Information Needs"
   End If
   ... (error trapping)
End Sub

And the ProcessOpenArgs sub (OpenArgs get set as "park;resource"):

Private Sub ProcessOpenArgs(open_args As String)
   On Error GoTo Err_ProcessOpenArgs

   Dim Args() As String
   Args = Split(open_args, ";")

   Me.unit_code = Args(0)
   Me.resource = Args(1)

   'Check to see if there are records in the database for current unit/resource combo'
   Dim rs As DAO.Recordset
   Dim sql As String
   sql = "SELECT * FROM PARK_RESOURCES " & _
    "WHERE resource='" & Me.resource & "' AND unit_code='" & Me.unit_code & "'"
   Set rs = CurrentDb.OpenRecordset(sql, dbOpenDynaset, dbSeeChanges)

   'if there aren''t, create a new record'
   If (rs.RecordCount = 0) Then
      New_Rec Me.unit_code, Me.resource, sql
   Else 'go to the current listing'
      Me.RecordSource = sql
   End If

Exit_ProcessOpenArgs:
   Exit Sub
Err_ProcessOpenArgs:
   MsgBox Err.Number & Err.description
   Resume Exit_ProcessOpenArgs
End Sub

I will continue to comb through the event documentation and as a last resort I may go totally nuts and just stick every possible event in my VBA code and step through them, but does anyone know what could be happening to cause the duplicates?

2
New_Rec is being called more than once with the same parameters. You didn't show how it gets called, so there's no way I could tell you. You could always update the New_Rec to check for the record before inserting it. It would take longer, but end the issue.Daniel
Thanks Daniel. I've included the calling code in case it might help, but wouldn't the debugger make 2 trips through New_Rec when I step through the code? It only goes through 1 time for me.MichaelJCox
In your ProcessOpenArgs, the If (rs.RecordCount = 0) Then line could be a problem unless you first use rs.MoveLast - see msdn.microsoft.com/en-us/library/ff821452%28v=office.14%29.aspxbarrowc
@barrowrc, your comment led me to the solution. Basically, when I'm setting Me.unit_code and Me.unit, the code is creating 1 record and then New_Rec inserts a second record in the DB. Then when the Form automatically Requeries it sticks the first record into the DB and pulls both back out to the Form Recordset. Your suggestion caused ProcessOpenArgs to throw Run Time Error 3201: No Current Record and then not execute New_Rec. The result being that only one record was created -- the record that had been started earlier in ProcessOpenArgs.MichaelJCox
As it seems to have helped, I made my comment into an answerbarrowc

2 Answers

1
votes

In your ProcessOpenArgs, the If (rs.RecordCount = 0) Then line could be a problem unless you first use rs.MoveLast - see here

1
votes

When I'm setting Me.unit_code and Me.unit here:

Private Sub ProcessOpenArgs(open_args As String)
   On Error GoTo Err_ProcessOpenArgs

   Dim Args() As String
   Args = Split(open_args, ";")

   Me.unit_code = Args(0)
   Me.resource = Args(1)

the code is creating 1 record and then New_Rec inserts a second record in the DB. When the Form automatically Requeries after Me.RecordSource = sql, it sticks the first record (created by the Me.xxx = yyyy statements in ProcessOpenArgs into the DB too and then pulls both back out to the Form Recordset. That's where the double insert is coming from.

In order to correct it, I changed Me.unit_code and Me.resource to local subroutine variables l_unit_code and l_resource and used those instead in ProcessOpenArgs. That took care of this problem as well as a second problem that I had with records form one resource type bleeding into other resource types.

Thanks all for the assist!