问题
In the process of answering this question, I wrote a simple function to test whether an MS Access table contained all fields in a supplied array:
Function ValidateFields(strTbl As String, arrReq As Variant) As Boolean
Dim fld
Dim fldTmp As Field
On Error GoTo err
For Each fld In arrReq
Set fldTmp = CurrentDb.TableDefs(strTbl).Fields(fld)
Next fld
ValidateFields = True
err:
Exit Function
End Function
?ValidateFields("TempTable", Array("Field1", "Field2", "Field3"))
False
This performs as expected, however, to improve the efficiency I tried assigning the Fields Collection to a variable outside of the For Each
loop:
Function ValidateFields(strTbl As String, arrReq As Variant) As Boolean
Dim fld
Dim fldTmp As Field
Dim colFld As Fields
Set colFld = CurrentDb.TableDefs(strTbl).Fields
On Error GoTo err
For Each fld In arrReq
Set fldTmp = colFld(fld)
Next fld
ValidateFields = True
err:
Exit Function
End Function
And now, if I comment out the On Error
statement, I receive the following error with the line Set fldTmp = colFld(fld)
highlighted as the cause:
Run-time error '3420':
Object invalid or no longer set.
Why would the variable colFld
lose its value within the For Each
loop?
回答1:
The problem here is:
CurrentDb
creates a DAO.Database
object of the currently open database. Your TableDef
is a member of that.
But since you're not storing that object, it gets closed and deallocated right after you copied the tabledef to an object, and with it the members will be deallocated too.
Store the database object, and the members will also persist:
Function ValidateFields(strTbl As String, arrReq As Variant) As Boolean
Dim fld
Dim fldTmp As Field
Dim colFld As Fields
Dim db As DAO.Database
Set db = CurrentDb
Set colFld = db.TableDefs(strTbl).Fields
On Error GoTo err
For Each fld In arrReq
Set fldTmp = colFld(fld)
Next fld
ValidateFields = True
err:
Exit Function
End Function
来源:https://stackoverflow.com/questions/56612992/object-invalid-or-no-longer-set-when-using-variable-to-reference-collection