Ответ 1
У меня была такая же проблема раньше, и просто добавление пустого события Form_Load
разрешило проблему. Никакой код не должен быть с Form_Load
, он просто должен присутствовать.
У меня есть разочаровывающая проблема в MS Access 2010, которую я бы на этом этапе квалифицировал как ошибку. И, пробовав все возможные обходные пути, я выхожу из идей и полагаюсь на вас.
Приложение Huge Ms Access 2010 с 25-килограммовыми линиями VBA и > 50 форм. Он имеет архитектуру клиентского сервера с объединенным интерфейсом и бэкендом доступа в сети. Он подключается к двум различным базам данных (Oracle/SQL Server/Sybase IQ).
Иногда, когда я назначаю набор записей ADODB для подформы, его данные не отображаются в связанных полях.20 >
Данные есть. Я могу debug.print
его, я вижу его в браузере Watches, я могу читать или манипулировать им, когда вы зацикливаете на объекте recordset с кодом. Он просто не отображается в подчиненной форме.
Он может работать безупречно в течение нескольких месяцев, и вдруг одна форма начнет иметь эту проблему без какой-либо видимой причины (это может произойти даже в тех формах, которые я не изменил). Когда это происходит, это делается для всех пользователей, так что это действительно что-то не так в интерфейсе accdb/accde.
Проблема не связана с конкретной СУБД/драйвером. Это может произойти с данными 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
recordsettype, проблема остается, если я пытаюсь dynaset
.
Dataentry, дополнение, удаление, изменения отключены. Это чистое чтение.
У меня есть привычка отключать записи с помощью RST.ActiveConnection = Nothing
, поэтому я могу манипулировать ими впоследствии, но это также не влияет на проблему.
Это может происходить с очень простыми запросами только с одним полем в предложении SELECT
и только с одним полем, привязанным к нему на подформе.
Реимпорт всех объектов в свежем accdb также не решает проблему.
Решение, предложенное random_answer_guy, с первого взгляда работало, что подтвердило гипотезу об ошибке. К сожалению, мои проблемы возникли после некоторых (тотально несвязанных) изменений в основной форме. Я вернулся с 4 или 5 подформами, не отображающими данные, и добавление/удаление события загрузки на всех или части из них больше не имеет никакого значения
Если вам нужна дополнительная информация о том, насколько странно эта проблема, я советую вам прочитать мой комментарий к отвечу random_answer_guy.
Чрезвычайно разочаровывает то, что у меня могут быть две разные формы с точно такими же свойствами и одинаковыми полями, одна и та же инструкция SQL над одним и тем же БД, один и тот же код управления наборами записей: один показывает данные, а другой нет!
Когда проблема возникает, у меня нет другого выбора, кроме как удалить все объекты, которые будут обрабатываться и реимпортироваться из старой версии, или воссоздать их с нуля.
Если это не ошибка, я все еще ищу подходящее слово, чтобы квалифицировать ее.
Кто-нибудь когда-либо сталкивался с этой проблемой и объяснил и/или обходное решение, чтобы предложить?
У меня была такая же проблема раньше, и просто добавление пустого события Form_Load
разрешило проблему. Никакой код не должен быть с Form_Load
, он просто должен присутствовать.
Таким образом, никто не мог дать на этом этапе четкий ответ на главный вопрос:
Почему эта ошибка происходит?
Тем временем я "элегантно" обошел проблему, изменив метод, используемый для подформ, сталкивающихся с ошибкой, от 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
Тем не менее, я бы предпочел получить объяснение и исправить: (