Reputation: 5
I have an Access 2016 function that checks a scripting dictionary's values against a database of historical values and returns a dictionary of key/item pairs that don't fall inside a calculated error range. However, the function is only returning the keys, and a call to the item results in a run-time error 3420 - Object invalid or no longer set.
I debug the dictionary at the end of the function, and it prints fine, but when the function returns, it bugs out.
Here's the simplified call to the function:
sub Verify(index as long, frm as form)
dim badComps as object
dim comp as variant
Set badComps = Check_History(INDEX, custID, Station)
For Each comp In badComps.Items
Debug.Print "'" & comp & "'"
Next
End Sub
And here's the function itself: (EDIT: The function works, so i simplified it. The debug statement at the end prints everything I need to return to the Verify Sub)
Function Check_History(INDEX As Long, ByVal frmCust As String, ByVal frmStat As String) As Scripting.dictionary
Dim avgs As Object, mPercents As Object, dict As Object
Dim rst As DAO.Recordset, rst2 As DAO.Recordset
Dim db As DAO.Database
Dim compName As Variant, badKeys As Variant
Dim i As Long
Set db = CurrentDb
Set mPercents = CreateObject("Scripting.Dictionary")
Set dict = CreateObject("Scripting.Dictionary")
'pull history for the passed station
Set rst = db.OpenRecordset("SELECT * FROM [tblCalculated_Values] WHERE [INDEX] = " & INDEX)
rst.MoveLast
'pull history for the passed station.
Set rst2 = db.OpenRecordset("SELECT * FROM [Sample History] WHERE [INDEX] = '" & frmCust & frmStat & "'")
If rst2.RecordCount = 0 Then GoTo nohist
rst2.MoveLast
rst2.MoveFirst
'calculate the average historical value for each component
For i = 0 To rst2.RecordCount - 1
For Each compName In mults.keys
If avgs.Exists(compName) Then
avgs.Item(compName) = avgs.Item(compName) + rst2.fields(compName)
Else
avgs.Add compName, rst2.fields(compName)
End If
Next
rst2.MoveNext
Next
rst2.MoveFirst
For Each compName In mults.keys
If avgs.Exists(compName) Then
If IsNull(avgs.Item(compName)) Then avgs.Item(compName) = 0
avgs.Item(compName) = avgs.Item(compName) / rst2.RecordCount
End If
Next
'If sample falls outside the range of avg +- 1, add error to dictionary
If mPercents.Item(compName) > 0 And avgs.Item(compName) > 0 Then
If mPercents.Item(compName) < WorksheetFunction.Max(0.001, Round(avgs.Item(compName) - 1, 3)) Or _
mPercents.Item(compName) > Round(avgs.Item(compName) + 1, 3) Then dict.Add compName, mPercents.Item(compName)
If dict.Exists(compName) Then Debug.Print compName, dict.Item(compName)
End If
Next
badKeys = dict.keys
'if no errors, add key = "clean" & item = 0, else return dictionary of component, avg value
If UBound(badKeys) = -1 Then dict.Add "clean", 0
Set Check_History = dict
nohist:
End Function
Any help/insight/tips would make my day a lot brighter. TIA!
Upvotes: 0
Views: 254
Reputation: 166456
Ignoring the other issues with your posted code, this:
avgs.Add compName, rst2.fields(compName)
is a little ambiguous: do you mean to add the Field object itself, or the field's Value ?
It looks like you mean to do the latter, but you actually are doing the former. So when your dictionary is returned from the function, it may contain references to your (now closed) recordsets.
Your Debug.Print
outputs are likely OK because the default Value
property gets called for creating the Print
outputs
avgs.Add compName, rst2.fields(compName).Value
should fix that.
Upvotes: 2