我在MS Access 2010上遇到了一个令人沮丧的问题,我现在在这个问题上有资格作为一个错误。在尝试了所有可能的解决方法之后,我没有想法并依赖于你。
拥有25k行VBA和> 50个表单的巨大Ms Access 2010应用程序。它有一个客户端服务器体系结构,其前端已编译,网络上有Access后端。它连接到二十多个不同的数据库(Oracle / SQL Server / Sybase IQ)。
有时,当我将ADODB记录集分配给子表单时,其数据不会显示在绑定字段中。我到处都有#Name?
数据就在那里。我可以debug.print
它,我可以在Watches浏览器中看到它,我可以在使用代码循环记录集对象时读取或操作它。它只是没有出现在子表单中。
它可以在几个月内完美地工作,并且突然一个表格将开始出现这个问题而没有任何明显的原因(甚至可能在我没有改变的表格上发生)。当它发生时,它适用于所有用户,所以这在前端accdb / accde中确实有问题。
该问题与特定的DBMS /驱动程序无关。 Oracle或Sybase数据可能会发生这种情况。
我创建了自己的类,抽象出与ADO连接和查询相关的所有内容,并在各处使用相同的技术。基于它,我得到了十分之一的表格,而且大多数表格都很完美。
我在我的应用程序的几个部分中遇到此问题,特别是在具有大量子表单和代码的高度复杂的表单中。 在这个主表单上,一些子表单有问题,而其他子表单没有。它们具有完全相同的参数。
这就是我填写表单记录集的方式:
Set RST = Nothing
Set RST = New ADODB.Recordset
Set RST = Oracle_CON.QueryRS(SQL)
If Not RST Is Nothing Then
Set RST.ActiveConnection = Nothing
Set Form_the_form_name.Recordset = RST
End If
使用Oracle_CON.QueryRS(SQL)
调用的代码是
Public Function QueryRS(ByVal SQL As String, Optional strTitle As String) As ADODB.Recordset
Dim dbQuery As ADODB.Command
Dim Output As ADODB.Recordset
Dim dtTemp As Date
Dim strErrNumber As Long
Dim strErrDesc As String
Dim intSeconds As Long
Dim Param As Variant
If DBcon.state <> adStateOpen Then
Set QueryRS = Nothing
Else
DoCmd.Hourglass True
pLastRows = 0
pLastSQL = SQL
pLastError = ""
pLastSeconds = 0
Set dbQuery = New ADODB.Command
dbQuery.ActiveConnection = DBcon
dbQuery.CommandText = SQL
dbQuery.CommandTimeout = pTimeOut
Set Output = New ADODB.Recordset
LogIt SQL, strTitle
dtTemp = Now
On Error GoTo Query_Error
With Output
.LockType = adLockPessimistic
.CursorType = adUseClient
.CursorLocation = adUseClient
.Open dbQuery
End With
intSeconds = DateDiff("s", dtTemp, Now)
If Output.EOF Then
LogIt "-- " & Format(Now, "hh:nn:ss") & " | Executed in " & intSeconds & " second" & IIf(intSeconds = 1, "", "s") & " | Now rows returned."
Set QueryRS = Nothing
Else
Output.MoveLast
pLastRows = Output.RecordCount
LogIt "-- " & Format(Now, "hh:nn:ss") & " | Executed in " & intSeconds & " second" & IIf(intSeconds = 1, "", "s") & " | " & Output.RecordCount & " row" & IIf(Output.RecordCount = 1, "", "s") & " returned."
Output.MoveFirst
Set QueryRS = Output
End If
End If
Exit_Sub:
pLastSeconds = intSeconds
Set Output = Nothing
Set Parameter = Nothing
Set dbQuery = Nothing
DoCmd.Hourglass False
Exit Function
Query_Error:
intSeconds = DateDiff("s", dtTemp, Now)
strErrNumber = Err.Number
strErrDesc = Err.DESCRIPTION
pLastError = strErrDesc
MsgBox strErrDesc, vbCritical, "Error " & pDSN
LogIt strErrDesc, , "ERROR"
Set QueryRS = Nothing
Resume Exit_Sub
Resume
End Function
对于记录集,我尝试了
的每个可能变体 .LockType = adLockPessimistic
.CursorType = adUseClient
.CursorLocation = adUseClient
处理记录集的子表单具有Snapshot
记录集类型,如果我尝试dynaset
,问题仍然存在。
数据条目,添加,删除,编辑均已禁用。这是纯粹的只读。
我习惯使用RST.ActiveConnection = Nothing
断开记录集,因此我可以在之后操作它们,但这也不会影响问题。
只有SELECT
子句中只有一个字段且子表单上只有一个字段绑定了一个非常简单的查询,就会发生这种情况。
重新导入新accdb中的所有对象并不能解决问题。
random_answer_guy 提出的解决方案乍一看是有效的,它可以验证错误假设。不幸的是,在主要形式的一些(完全不相关的)变化之后,我的问题再次出现。我回来了4或5个不显示数据的子表单,并且在全部或部分上添加/删除Load事件不再有任何区别
如果您想了解有关此问题有多奇怪的更多信息,建议您阅读我对 random_answer_guy 的答案的评论。
令人非常沮丧的是,我可以拥有2个不同的表单,具有完全相同的属性和相同的字段,相同的DB指令,相同的记录集管理代码:一个显示数据,另一个不显示数据!
当问题发生时,除了删除所有被操纵的对象并从旧版本重新导入它们或从头开始重新创建它们之外我别无选择。
如果这不是一个错误,我仍然在寻找合适的词来进行限定。
有没有人遇到过这个问题并提出解释和/或解决方法?
答案 0 :(得分:7)
之前我遇到过同样的问题而只是添加一个空白的Form_Load
事件解决了这个问题。没有代码需要与Form_Load
只需要存在。
答案 1 :(得分:1)
所以没有人能够在这个阶段给出一个明确的答案:
为什么会发生此错误?
与此同时,我“优雅地”通过更改用于遇到错误的子表单的方法(从ADO到DAO)来绕过问题。
我在我的ADO抽象类中创建了一个新方法,它实际上使用DAO来返回记录集(不合逻辑,但是嘿......)。
我将数据传递给表单的代码变为:
Set RST = Nothing
Set RST = Oracle_CON.QueryDAORS(SQL)
If Not RST Is Nothing Then
Set Form_the_form_name.Recordset = RST
End If
这里的方法是QueryDAORS
:
Public Function QueryDAORS(ByVal SQL As String, Optional strTitle As String) As DAO.Recordset
Dim RS As DAO.Recordset
Dim dtTemp As Date
Dim strErrNumber As Long
Dim strErrDesc As String
Dim intSeconds As Long
Dim Param As Variant
On Error GoTo Query_Error
dtTemp = Now
If DBcon.state <> adStateOpen Then
Set QueryDAORS = Nothing
Else
DoCmd.Hourglass True
Set pQDEF = CurrentDb.CreateQueryDef("")
pQDEF.Connect = pPassThroughString
pQDEF.ODBCTimeout = pTimeOut
pQDEF.SQL = SQL
pLastRows = 0
pLastSQL = SQL
pLastError = ""
pLastSeconds = 0
LogIt SQL, strTitle, , True
Set RS = pQDEF.OpenRecordset(dbOpenSnapshot)
intSeconds = DateDiff("s", dtTemp, Now)
If RS.EOF Then
LogIt "-- " & Format(Now, "hh:nn:ss") & " | Executed in " & intSeconds & " second" & IIf(intSeconds = 1, "", "s") & " | Now rows returned."
Set QueryDAORS = Nothing
Else
RS.MoveLast
pLastRows = RS.RecordCount
LogIt "-- " & Format(Now, "hh:nn:ss") & " | Executed in " & intSeconds & " second" & IIf(intSeconds = 1, "", "s") & " | " & RS.RecordCount & " row" & IIf(RS.RecordCount = 1, "", "s") & " returned."
RS.MoveFirst
Set QueryDAORS = RS
End If
End If
Exit_Sub:
pLastSeconds = intSeconds
Set RS = Nothing
DoCmd.Hourglass False
Exit Function
Query_Error:
intSeconds = DateDiff("s", dtTemp, Now)
strErrNumber = Err.Number
strErrDesc = Err.DESCRIPTION
pLastError = strErrDesc
MsgBox strErrDesc, vbCritical, "Error " & pDSN
LogIt strErrDesc, , "ERROR"
Set QueryDAORS = Nothing
Resume Exit_Sub
Resume
End Function
属性pPassThroughString
是使用我在类中使用的属性使用另一个方法定义的,因为它们是打开与数据库的ADO连接所必需的:
Private Function pPassThroughString() As String
Select Case pRDBMS
Case "Oracle"
pPassThroughString = "ODBC;DSN=" & pDSN & ";UID=" & pUsername & ";Pwd=" & XorC(pXPassword, CYPHER_KEY)
Case "MS SQL"
pPassThroughString = "ODBC;DSN=" & pDSN & ";DATABASE=" & pDBname & ";Trusted_Connection=Yes"
Case "Sybase"
pPassThroughString = "ODBC;DSN=" & pDSN & ";"
Case Else
MsgBox "RDBMS empty ! ", vbExclamation
LogIt "RDBMS empty ! ", , "ERROR"
End Select
End Function
因此,只需将分配给表单的记录集从ADODB.Recordset
更改为DAO.recordset
并将调用的方法从.OpenRS
调整为.OpenDAORS
,即可快速解决问题。
唯一的问题是,使用DAO我不能再使用它来断开记录集:
Set RST.ActiveConnection = Nothing
尽管如此,我还是希望得到解释和解决方法:(