【问题标题】:How do I bring up a record based on a combobox in Access?如何根据 Access 中的组合框调出记录?
【发布时间】:2011-03-25 00:26:37
【问题描述】:

在 MS Access 中,我有一个简单的数据输入表单。在屏幕底部,您可以单步浏览记录并在每次点击时更新表单:

    
(来源:yfrog.com

如何通过表单上的组合框执行此操作?也就是说,我希望能够从列表中快速选择一个项目并让表单显示 that 项目。

【问题讨论】:

  • 编辑说明:当我陷入使用 LOLCats 的低、低水平时,这个问题在 2 小时 45 分钟后有 3 个视图......让我放松一下
  • 我认为lolcat 没有任何问题,毫无疑问,它是对lolcode 的编程参考。 -)

标签: ms-access forms


【解决方案1】:

在评论@Remou 的完全有效和有用的答案时,我提到了查找组合框向导创建了非常糟糕的代码这一事实。这是您为绑定列选择自动编号 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

其中一个问题是您不能在现有控件上运行它,因此您最终会得到一个随机命名的组合框,并且当您更改组合框的名称时,您必须将其重新应用于事件,并对其进行编辑以反映名称的更改。但与向导代码 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

首先,完全没有理由定义任何类型的记录集变量,因为您可以轻松地直接对适当的记录集进行操作。

其次,如果你声明它,将它声明为 Object 变量确实是相当防御性的编程。鉴于 .FindFirst 仅适用于 DAO 记录集,它始终是 DAO 记录集,它是其余代码可以处理的唯一记录集类型(无论表单的 Recordset 对象是否始终是 DAO 记录集——我'甚至不确定这是真的)。因此,只有在应用程序中没有 DAO 引用的情况下才需要使用 Object 类型变量。

这似乎过于谨慎,但我的主要观点是,首先没有理由声明变量。

第三,如果你给变量赋值了一个记录集,你需要自己清理一下,在sub的末尾设置变量为Nothing,并关闭form的记录集的克隆你创建的。

第四,没有理由使用表单记录集的克隆,因为 RecordsetClone 已经存在,其存在的全部原因正是这种用法。

第五,在组合框中处理 Null 值是疯狂的——继续克隆记录源,即使您不会找到任何东西对我来说也没有任何意义。如果它为 Null,则只需退出子程序(或为退出点创建标签并跳转到该点),而不是经历克隆记录集的麻烦并执行可以被认为是徒劳的 FindFirst 操作。

第六,FindFirst 效率不高——它对字段的索引进行顺序扫描,如果没有索引,它会通过表本身进行扫描——所以如果你一开始就不需要启动它,你应该避免启动它.

第七,如果组合框为 Null 时使用 Nz() 返回 0,如果 0 实际上是被搜索字段的有效值,则会产生不正确的结果。

第八,即使您从查找组合框中删除了值,也执行 FindFirst 会将当前记录移回第一个记录,而逻辑行为是将当前记录留在您之前的任何位置从查找组合框中删除了该值。也就是说,如果您不搜索,就不要找到任何东西!

第九,使用 EOF 作为您的测试假设 FindFirst 进行表扫描而不是索引扫描(我不知道它是否这样做),并且 FindFirst 甚至在克隆的记录集中移动指针如果没有结果(与没有结果时相反)。

第十,当每个记录集都有一个 NoMatch 属性正是为此目的而没有其他目的时,为什么要使用 EOF?在 FindFirst 命令之后进行测试时,它的含义没有歧义,与 EOF 不同,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 向导生成的代码形成鲜明对比——在某些情况下,我可能会发现它们有点过于冗长,但在可扩展性方面有充分的理由。我简直无法理解为什么这个特定的向导会产生如此糟糕的代码。

【讨论】:

  • 如果它是您要搜索的文本字段....FindFirst "[InventoryID] = " & "'" &Me!cmbFind & "'"
  • 这非常有用。感谢您的宝贵意见。我的组合框将包含 20,000 多条记录。使用您的代码,我能够使用文本框提取特定记录。
【解决方案2】:

您可以使用向导将组合框添加到绑定的表单中。向导提供的选项之一是“根据我在组合框中选择的值在我的表单上查找记录”。如果您的表单很复杂,您可能看不到此选项,在这种情况下,请创建一个简单的表单以查看向导并生成示例代码 - 并不总是最好的代码,但肯定非常有用。

有一些小事情可能会或可能不会给您带来麻烦,例如,如果用户在不使用组合的情况下移动到记录,则组合不会更改为显示新记录,但这很容易解决在表单的当前事件中添加一些代码。

【讨论】:

  • 不要使用自动生成的代码,因为它充满了每行代码大约一个错误。
  • @david-W-Fenton 每次我推荐使用向导时你都会这么说。该代码有效,它可能不是最好的,但如果您以前没有这样做过,它是一个非常有用的指南。如果您愿意为每个向导发布一页代码,我会不时引用它。
  • 是这个特殊的向导创建了如此灾难性的代码,而不是所有代码。我正在添加我自己的答案,显示向导代码,指出它有什么问题以及它应该是什么。
【解决方案3】:

您可以使用来自该组合框的条件作为表单行源的基础,即

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

然后在更新事件后的组合框上放这行代码

Me.Requery

这应该可以解决问题,但我已经有一段时间没有使用绑定表单了

【讨论】:

  • 这意味着表单现在只显示一条记录,并且无法再以任何其他方式浏览记录集。通常,用户喜欢不止一种导航方式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-28
  • 1970-01-01
  • 2017-08-24
相关资源
最近更新 更多