Как вызвать запись, основанную на комбинированном списке в Access? - PullRequest
6 голосов
/ 04 августа 2010

В MS Access у меня есть простая форма ввода данных. В нижней части экрана вы можете просматривать записи и обновлять форму при каждом нажатии:

доступ к предыдущему следующему бару http://a.yfrog.com/img62/2654/5ge.png

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

Ответы [ 3 ]

13 голосов
/ 05 августа 2010

Комментируя совершенно правильный и полезный ответ @ Remou, я упомянул тот факт, что мастер поиска комбинированного окна создает действительно плохой код.Вот код, который создает мастер, когда вы выбираете Autonumber PK для связанного столбца (существует небольшой разброс кода, который создает мастер, если вы ищете в текстовом поле вместо числового, но этого недостаточно для упоминания):

  Private Sub Combo2_AfterUpdate()
    ' Find the record that matches the control.
    Dim rs As Object

    Set rs = Me.Recordset.Clone
    rs.FindFirst "[InventoryID] = " & Str(Nz(Me![Combo2], 0))
    If Not rs.EOF Then Me.Bookmark = rs.Bookmark
  End Sub

Единственное, что не так с этим, это то, что вы не можете запустить его на существующем элементе управления, поэтому вы получаете комбинированное окно со случайным именем, и когда вы изменяете имя комбинированного окна, вы должны повторно применитьэто к событию, и отредактируйте это, чтобы отразить изменение имени.Но это относительно незначительно по сравнению с другими проблемами в самом коде мастера, который имеет ошибку не менее 2,5 проблем на строку созданного кода.

Вот мой альтернативный код:

  Private Sub cmbFind_AfterUpdate()
    If IsNull(Me!cmbFind) Then Exit Sub

    With Me.RecordsetClone
      .FindFirst "[InventoryID] = " & Me!cmbFind
      If Not .NoMatch Then
         If Me.Dirty Then Me.Dirty = False
         Me.Bookmark = .Bookmark
      Else
         ' put your not found code here, but you really shouldn't need it
      End If
    End With
  End Sub

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

Во-вторых, если вы do объявите ее, это действительно довольно защитное программирование, чтобы объявить его как переменную объекта.Учитывая, что .FindFirst работает только с набором записей DAO, это всегда будет набор записей DAO, который является единственным типом набора записей, с которым может работать остальная часть кода (независимо от того, является ли объект Recordset формы всегда набором записей DAO - яЯ даже не уверен, что это правда).Таким образом, использование переменной типа Object необходимо только в том случае, если вы работаете без ссылки на DAO в своем приложении.

Это кажется слишком осторожным, но моя главная мысль заключается в том, что нет никакой причины объявлять переменную в первую очередь.

В-третьих, если вы делаете назначаете набор записей для переменной, вам нужно очистить после себя и установить переменную Nothing в конце подпрограммы и закрыть клонсозданный вами набор записей формы.

В-четвертых, нет причин использовать клон набора записей формы, поскольку RecordsetClone уже существует, и вся причина его существования именно для этого вида использования.

В-пятых, обработка значения Null в поле со списком сумасшедшая - идти вперед и клонировать источник записей, даже если вы не собираетесь ничего находить, для меня нет смысла.Если это Null, просто выйдите из подпрограммы (или создайте метку для точки выхода и перейдите к ней), вместо того, чтобы заниматься клонированием набора записей и выполнять операцию FindFirst, которая, как известно, может быть бесплодной.

В-шестых, FindFirst неэффективен - он выполняет последовательное сканирование по индексу поля или по самой таблице, если индекса нет, поэтому вы хотите избежать его инициации, если вам не нужнопервое место.

Седьмое, использование Nz () для возврата 0, если поле со списком равно Null, даст неправильные результаты, если 0 действительно допустимое значение для искомого поля.

Восьмое,выполнение FindFirst, даже если вы удалили значение из поля со списком поиска, перемещает текущую запись обратно в первую, и вместо этого логичным было бы оставить текущую запись, где бы она ни находилась, прежде чем вы удалили значение изнайти поле со списком.То есть, если вы не ищете, ничего не находите!

Девятое, использование EOF в качестве теста предполагает, что FindFirst выполняет сканирование таблицы, а не индексное сканирование (я не знаю, что этоделает или не делает), и что FindFirst перемещает указатель в клонированном наборе записей, даже если результатов нет (в отличие от того, когда их нет).

В-десятых, зачем использовать EOF, когда каждый набор записей имеет свойство NoMatch именно для этой цели, а не для других? Не существует двусмысленности относительно того, что это означает при тестировании после команды FindFirst, в отличие от EOF, который сообщает, достиг ли указатель записи конца таблицы или нет. Одно свойство, NoMatch, имеет узкое значение и не может означать ничего другого и существует именно для использования после операции FindFirst, тогда как EOF имеет гораздо более широкое значение, которое используется здесь в качестве прокси для чего-то другого.

Одиннадцатым и наиболее серьезным недостатком является то, что код мастера явно не заставляет СОХРАНИТЬ, если запись загрязнена перед установкой закладки. Это критическая ошибка, поскольку в этой области доступ ненадежен на протяжении многих лет - ошибки, которые происходят из-за неявного сохранения, инициируемого отправкой исходной записи путем установки закладки, могут быть потеряны и привести к потере данных. Теоретически, это ошибка, которая была исправлена ​​давным-давно, но явным образом рекомендуется принудительно сохранять сохранение перед переходом к другой записи, поскольку вы допускаете, чтобы любые ошибки в операции сохранения возникали с отступом от операции навигации.

Должен ли я сказать больше?

Почему так? Моим первым предположением было бы то, что мастер создает один и тот же код в MDB / ACCDB и в ADP, но формы ADP не могут возвращать наборы записей DAO, поэтому у вас не будет FindFirst. Возможно, в ADP он использует Find вместо FindFirst. Это объясняет, почему вместо NoMatch используется EOF, поскольку в наборах записей ADO отсутствует NoMatch.

Но почему мои MDB / ACCDB должны быть ограничены требованиями ADP, который не имеет к ним никакого отношения? И если я прав, что существует условный код для определения того, использовать ли Find или FindFirst, тогда почему бы не использовать все возможности и использовать наиболее подходящие методы в контексте, в котором запускается мастер?

Это ужасный код, и его нужно переписывать при каждом вызове мастера. Это мог бы быть лучший код, но по какой-то неизвестной причине MS решила создать испорченный код. Это довольно сильно отличается от кода, созданного всеми другими мастерами Access, которые я когда-либо использовал - в некоторых случаях я могу счесть их слишком многословными, но для этого есть хорошее оправдание с точки зрения расширяемости. Я просто не могу понять причину, почему этот конкретный волшебник производит такой ужасный код.

3 голосов
/ 04 августа 2010

Вы можете использовать мастера, чтобы добавить комбинированный список в вашу связанную форму. Один из вариантов, предлагаемых мастером, - «Найти запись в моей форме на основе значения, которое я выбрал в своем поле со списком». Если ваша форма сложная, вы можете не увидеть эту опцию, в этом случае создайте простую форму для просмотра мастера и сгенерируйте пример кода - не всегда лучший код, но, безусловно, очень полезный.

Есть несколько мелких вещей, которые могут вас беспокоить или не беспокоить, например, если пользователь переходит к записи без использования комбо, комбо не меняется, чтобы показать новую запись, но это очень легко исправить с небольшим кодом в текущем событии для формы.

0 голосов
/ 04 августа 2010

Источник строки формы будет основан на критериях из этого поля со списком, т. Е.

SELECT * FROM tblFoo WHERE bar=forms!frmMyForm!cboBar

Затем в поле со списком после обновления введите эту строку кода

Me.Requery

Это должно сработать, но прошло много времени с тех пор, как я работал со связанными формами

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...