Как я поднимаю запись на основе поля комбинированного списка в Доступе?

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

    access previous next bar
(источник: yfrog.com)

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

7
задан Glorfindel 4 August 2019 в 19:09
поделиться

3 ответа

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

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

4
ответ дан 6 December 2019 в 10:46
поделиться

Вы должны основывать источник строки формы с критериями из этого поля со списком, т.е.

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

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

Me.Requery

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

-1
ответ дан 6 December 2019 в 10:46
поделиться

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

  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

Единственное, что здесь не так, это то, что вы не можете запустить его на существующем элементе управления, поэтому вы получите поле со списком со случайным именем, и когда вы измените имя поля со списком, вам придется повторно применить его к событию, и отредактируйте его, чтобы отразить изменение имени. Но это относительно незначительно по сравнению с другими проблемами в коде мастера itelf, у которого частота ошибок составляет не менее 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

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

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

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

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

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

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

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

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

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

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

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

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

Мне нужно сказать больше?

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

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

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

15
ответ дан 6 December 2019 в 10:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: