Почему я не могу загрузить подчиненную форму, когда она связана с указанной c хранимой процедурой? - PullRequest
1 голос
/ 11 марта 2020

Сводка

В базе данных Microsoft Access 2010 (accdb) у меня есть форма, которая динамически загружает другие формы в объект подчиненной формы в главной форме. Формы, используемые в объекте подчиненной формы, привязаны к сквозным запросам ODB C, которые выполняют хранимые процедуры для возврата наборов записей. Я не могу понять, почему я могу использовать одно spro c, и оно прекрасно работает, но если я привяжу форму к другому spro c, она не сможет загрузить подчиненную форму.

Техническое руководство

У меня есть два сквозных запроса ODB C. qryGood и qryBad. Они используют идентичные строки подключения ODB C (ODBC;DRIVER=SQL Server;SERVER=MyServer;UID=MyUser;Trusted_Connection=Yes;DATABASE=MyDatabase), а SQL за ними идентичны, но указывают на две разные хранимые процедуры SQL на сервере базы данных SQL 2012.

Источник qryGood: exec spGoodProc 123456

Источник qryBad: exec spBadProc 123456

SQL за спро c очень просто. Возврат записей из одной таблицы с фильтрацией по идентификатору, переданному в качестве параметра. (Некоторые будут делать более сложные вещи, но я просто остановлюсь на упрощенном примере, который демонстрирует проблему.)

Свойство RecordSource frmMySubform установлено в qryBad.

Субформа SourceObject устанавливается с помощью кода VBA: sfrmMain.SourceObject = "frmMySubform" На этом этапе ошибки не выдаются. В то время как свойство SourceObject теперь возвращает frmMySubform, объект .Form, похоже, не установлен.

Затем я пытаюсь сослаться на свойство в подчиненной форме: Debug.Print sfrmMain.Form.Name Сбой с ошибкой 2467: Введенное вами выражение относится к объекту, который закрыт или не существует.

Затем я могу открыть frmMySubform в режиме конструктора, изменив свойство RecordSource на qryGood и это работает просто отлично. Кажется, это указывает на проблему с spBadProc, которая проявляется только при использовании в качестве RecordSource в подчиненной форме.

Что я пытался

В попытке устранить эту проблему, Я использовал процесс исключения, чтобы сузить это, насколько я могу, но я все еще не понимаю, почему один spro c работает, а другой нет. Обе записи возвращаются просто отлично в SQL и при непосредственном выполнении сквозного запроса. Оба работают нормально при открытии формы напрямую. Это становится проблемой только тогда, когда форма установлена ​​как SourceObject в элементе управления подчиненной формы.

Я использовал sp_procedure_params_rowset для сравнения параметров в sprocs, и они идентичны. Я сравнил типы данных столбцов в SQL, и нет ничего нового или отличного в tblBad, которого нет в tblGood. Я также попытался профилировать сервер SQL при настройке формы, и кажется, что spro c вызывает нормально. Я не видел никаких подсказок при сравнении трассировки между плохими и хорошими звонками.

Установка RecordSet напрямую на ODB C ссылка на tblBad работает просто отлично (и я предполагаю, что представление также будет в порядке), но наличие простой оболочки хранимых процедур каким-то образом вызывает ошибку.

Я также сравнил безопасность, свойства и расширенные свойства для spGoodProc и spBadProc, и они идентичны.

Мой вопрос

Что я могу сделать на стороне устранения неполадок, чтобы еще больше уменьшить это? Кто-нибудь сталкивался с подобными проблемами со связанными sprocs на подчиненных формах? Я работаю над очень сложной базой данных с сотнями форм, таблиц и запросов, поэтому мне бы очень хотелось понять, почему это происходит, прежде чем я go слишком далеко по этому пути.

Заранее благодарим вас за любые идеи, которыми вы можете поделиться по этой озадачивающей проблеме. :-)

Ответы [ 2 ]

0 голосов
/ 12 марта 2020

Имейте в виду, что источник данных подчиненной формы будет пытаться загрузить ДО загрузки основной формы. Это говорит о том, что в событии загрузки главной формы вы

сначала настроите запрос PT. Затем задайте источник OBJECT для формы.

Другими словами, исходный объект элемента управления формы должен быть пустым.

Тогда вы создадите код для настройки PT-запроса:

With currentdb.queryDefs("qryGood")
   .SQL = "EXEC spGoodProc " & 123456
end with

Конечно, вы можете заменить 123456 переменной или даже значением из текстового поля (из основной формы).

Теперь, когда PT-запрос настроен, вы ТОГДА установить форму, которую должна загружать подформа.

Итак, после кода выше, мы имеем:

me.mySubForm.SourceObject = "name of subform goes here"

Итак, всего должно быть около 4 строки кода. И, как показано выше, вам даже не нужны какие-либо строки подключения в вашем коде VBA.

Итак, просто имейте в виду: настройте запрос PT, как описано выше. Затем вы можете запустить отчет, или даже форму, или в этом случае установить форму, которую должен загрузить элемент управления формы. Это также предлагает / намекает на то, что вам нужно удалить исходный объект элемента управления формы (оставьте это поле пустым).

Вы можете установить исходный объект sub-from, но тогда это будет означать, что вы настроили Источник запроса PT, как указано выше, ДО того, как вы запустите основную форму с подформой, основанной на запросе PT. Как уже отмечалось, этот набор шагов необходим, поскольку подформа фактически загружает и разрешает свой источник данных ДО того, как основная форма отобразит и отобразит. Таким образом, оставив исходный объект пустым для формы, разработчик вновь получает полный контроль над порядком загрузки.

0 голосов
/ 11 марта 2020

Нашел его!

После его трассировки к таблице с указанным значением c я удалил все ограничения, ключи, а затем столбцы из копии таблицы, систематически проверяя, не могу ли я точно определить проблему. Конечно же, это было заданное c имя столбца в хранимой процедуре!

Простое наложение этого столбца на другое имя решило проблему. (подробности см. Ниже)

Обновление после дальнейшего тестирования

После дополнительного тестирования для дальнейшего выявления проблемы, я думаю, теперь я понимаю, почему это происходит. Когда вы связываете таблицу ODB C и указываете уникальный (ключевой) столбец, Access автоматически пытается установить LinkMasterFields и LinkChildFields для ключа Имя столбца, когда подчиненная форма загружена, и у подчиненной формы есть столбец с тем же именем. Хотя это прекрасно работает с связанными таблицами или представлениями , оно не работает, когда RecordSource для подчиненной формы установлена ​​ хранимая процедура .

Если вы попытаетесь сделать это вручную, добавив подчиненную форму, вы увидите следующее уведомление:

pass-through query error message

Однако, если вы установите цель подчиненной формы с помощью кода VBA, вы не получите никаких предупреждений или сообщений об ошибках. Он просто не (полностью) загружает подчиненную форму. @ Альберт Д. Каллал , вы были правы относительно того, что это связано с проблемой основных / дочерних полей!

Мне удалось последовательно воспроизвести проблему в файле тестовой базы данных в обоих Access 2010 и Access 2016. Если вы хотите убедиться в этом сами, вы можете использовать следующие шаги для его воспроизведения:

  1. Создайте таблицу SQL со столбцом PrimaryID.
CREATE TABLE [dbo].[tblBugTest](
    [PrimaryID] [int] NOT NULL,
    [TestColumn] [nchar](10) NULL
) ON [PRIMARY]
Добавьте пару тестовых записей в таблицу, которую вы только что создали. Создайте хранимую процедуру для возврата записей.
CREATE PROCEDURE [dbo].[spBugExample]
AS SELECT * FROM tblBugTest
Создайте пустую базу данных Microsoft Access (accdb). Используя ODB C, создайте связанную таблицу для tblBugTest.
  • Внимание! Выберите PrimaryID в качестве уникального столбца.
Создайте сквозной запрос с именем qryPassThrough, используя ODB C для той же базы данных, и установите SQL на exec spBugExample.
  • Откройте запрос, чтобы убедиться, что он возвращает записи.
Создайте три пустые формы в базе данных. frmMain, frmSubForm и frmBlank. Добавить frmBlank в качестве подчиненной формы к frmMain. Назовите подчиненную форму sfrmSubform. Установите RecordSource из frmMain для связанной таблицы . Добавьте кнопку в frmMain для переключения подчиненной формы от frmBlank до frmSubForm.
Private Sub cmdShowBug_Click()
    With Me.sfrmSubform
        .SourceObject = "frmSubForm"
        Debug.Print .LinkMasterFields
        Debug.Print .LinkChildFields
        Debug.Print .Form.Name
        .SourceObject = "frmBlank"
    End With
End Sub
Установите RecordSource для frmSubForm на qryPassThrough. Перетащите пару связанных элементов управления на frmSubForm.
  • Тест frmSubForm сам по себе. Он должен загрузить запись из tblBugTest.
Открыть frmMain и нажать кнопку. Должно появиться сообщение об ошибке.

Если вы пройдете по коду, вы увидите, что перед установкой SourceObject свойство LinkMasterFields пустое. После установки SourceObject вы можете навести курсор на LinkMasterFields и увидеть, что теперь он установлен на столбец PrimaryID.

enter image description here

Обходные пути

Изменение любого из следующих параметров поможет обойти ошибку, исключив проблемное c автоматическое связывание полей master / child.

  • На этот раз удалите и заново связайте связанную таблицу не указывается уникальный столбец.
  • Псевдоним столбца в хранимой процедуре отличается от имени уникального столбца.
  • Очистите свойство RecordSource родительской формы.
  • Очистить свойство RecordSource подчиненной формы и установите RecordSet после загрузки подчиненной формы.
  • Используйте представление или связанную таблицу вместо хранимой процедуры в подчиненной форме.
...