MS Access:容器对象Forms属于什么对象模型?

MS Access: What object model does the container object Forms belong to?

据我了解,DAO 和 ADO 对象模型只有用于数据访问的对象,例如 tables 和查询,而没有与数据表示相关的对象,例如表单和报告。

同意这一点,MS documentation of DAO objects 中的一长串对象不包括表格或报告。

同样同意,MS documentation on the DAO container object 说 "The following table lists the name of each Container object defined by the Microsoft Access database engine" 并且说 table 列出了三个对象:数据库、表和关系。

但是,当我运行在Access 2007中执行以下例程时VBA:

Sub ListDocuments()

Dim oDB As DAO.Database: Set oDB = CurrentDb()
Dim oContainer As DAO.Container

For Each oContainer In oDB.Containers
    Debug.Print oContainer.Name
  Next oContainer

End Sub

我得到以下输出:

DataAccessPages
Databases
Forms
Modules
Relationships
Reports
Scripts
SysRel
Tables

这个输出有两个问题:

这个容器对象 Forms 似乎没有在任何地方记录。而它的存在似乎与上面引用的Access只定义了三个容器对象的说法相矛盾。而且,由于它在 DAO 对象 Containers 中,这似乎也与 DAO 不包含表单和报表对象的想法相矛盾。

那么我的问题是,这个容器对象Forms是从哪里来的呢?它属于什么对象模型?如果您知道答案,如果您可以 link 一些相关文档,将会很有帮助。

来自:

Microsoft Access

您可以轻松查看:

? Forms.Parent.Name
Microsoft Access

这包含所有表格,无论是否打开:

Application.CurrentProject.AllForms

当前数据库指的是那个容器。这些将 return 相同计数:

? CurrentDb.Containers(acForm).Documents.Count
? Application.CurrentProject.AllForms.Count

CurrentDb(或任何其他 DAO.Database 对象)可能是 DAO 出现的地方 - 在您参考的文档中.

这里没什么好写的。

Access 有一些“容器”对象。我们可以在这些容器中存储图片、PDF 文档或其他任何内容。

我们甚至可以在这些容器中存储关系图。 (哦,等等——他们做到了!!!)。

容器就是 Access 应用程序中的一些容器。

因此,它们可以非常任意地成为 Access 应用程序设计者希望存储在容器中的任何内容。

我的意思是,真的,这与 table 没有太大区别。 table 可能有发票,或者说有一些客户

然后推断 DAO 具有“客户”对象或“发票”对象作为 DAO 对象模型的一部分在这里没有什么意义。

容器“对象”就是一个容器。它们与 DAO 对象模型关系不大。

“容器”是由 Access 系统而非 DAO 提供的对象列表。

DAO 对象模型没有“容器”方法或“容器”属性。

公平地说,Access 中使用的“本机”数据库引擎是 JET(现在称为 ACE)。公平地说,由于访问数据库引擎与 DAO 对象模型的联系非常紧密,因此可以肯定地说,Access(开发人员工具)与 DAO 的联系远比与 ADO 的联系紧密。

虽然您可以最自由地使用 DAO 或 ADO 从 JET/ACE 引擎中获取数据,但在这里 DAO 无疑是首选。

这种偏好的“主要”原因是 DAO 与 JET/ACE 数据库引擎紧密相关。 Access 最初是围绕 JET + dao 库代码构建的,因此它的根与 DAO 对象模型更加紧密。

但是,如果你要从SQL服务器上抓取数据,那么长期以来,大多数开发人员更喜欢ADO对象模型。当说使用 SQL 服务器或说 MySQL 或 Oracle 作为后端数据库以及 MS-access 作为前端时,使用 ADO 有几个优点。

使用 ADO 的“主要”优点是,用于 ADO 的 SQL“更接近”“行业”标准 (ansi-92) 使用的 SQL 语法。因此,如果您使用 SQL 服务器或将 Oracle 作为后端,您使用 ADO 编写的 SQL 将(通常)无需更改即可工作。 (而且您可以在两个数据库之间切换而无需更改您使用的 sql 语法)。

对于 DAO,您使用的是 Access (jet) SQL 语法,或者更好地说,JET/ACE 语法。当您使用 ADO,但仍然使用 JET/ACE 引擎时,您可以使用 sql ansi-92 语法。结果是 sql 的语法将更匹配 SQL 服务器上使用的语法,或者说 oracle。

对于 access + JET/ACE 应用程序,推荐的标准选择是使用 DAO。 (18 年前,Microsoft 在 Access 2000 中将“默认”对象模型更改为 ADO。开发人员上演了一场“反抗”,在 Access 2003 中,他们将 DAO 作为默认值返回。(直到今天,您仍然可以选择对象模型,或者更糟的是将两者“混合”——不要去那里!!!)。所以微软没有强制改变,但“默认”设置是 ADO——但我们总是将引用改回 DAO 并保留像往常一样编写代码。

因此,多年来,Microsoft 一直在推动所有人使用 ADO,包括非常流行的 MS-access 系统。

然而,我们大多数开发人员都忽略了微软的这一建议,并在构建本机访问应用程序时继续使用 DAO。如前所述,在相当长的一段时间内,DAO 是默认的对象模型。因为 DAO 在某种程度上被“弃用”,Access 团队采用了 DAO 对象和代码库,他们现在拥有这个库。 (之前它只是一个所有开发人员都可以使用的标准 Microsoft 库)。所以对于V6,vb.net等,他们倾向于使用ADO。

因此您现在可以“读到”DAO 已被弃用,但 Access 使用 ACE 数据库引擎中包含的更新版本。 (因此,虽然作为独立对象库的 DAO 已被贬低,但 DAO 代码会更新,并且新功能会继续作为 ACE 数据引擎对象在 Access 中使用。

当您设置对 ACE 数据引擎的引用时,您的所有 DAO 代码都应该可以正常工作。 这意味着什么(自 access 2007 起),您不需要设置对 DAO 对象模型的外部引用——它现在是 JET/ACE 数据库引擎的一部分。 (在访问 2007 之前,您必须设置对 DAO 的引用。如果您要使用 ADO,则始终必须设置该引用,直到今天您仍然这样做)

进行此更改是因为实际上只有 Access 社区和开发人员在使用 DAO——大多数其他平台都在使用 ADO(出于多种原因,但一个重要原因是 ADO 没有绑定,也没有起源于像 DAO 一样的 MS-access 数据库引擎,直到今天仍然如此。

请记住,在大约 5-10 年的时间里,Microsoft 没有 SQL 服务器,因此 Access + DAO 是他们的“大手笔”。当他们最终开始销售 SQL 服务器时,微软推动 DAO 的事情当然发生了变化。 DAO 是“主要的”MS 访问数据引擎技术。

如果您将来将数据从 Access 移动到 sql 服务器,并继续使用 MS-access 作为 GUI 前端,access 社区仍然建议您坚持使用任何对象模型用于开发您的应用程序。因此访问使用 DAO 开发的应用程序,但使用 sql 服务器作为后端数据库工作得很好,应该保持原样。

并且如果您使用 ADO 进行开发,那么如果您开始使用带有 Access 的 SQL 服务器,您希望继续。请注意,我说的是您编写的 VBA 代码——特定的 ADO 记录集。

您仍然始终使用 Access 中存在的“相同”内部容器——如果您在编写代码以修改 Access 客户端中的数据时使用 ADO 或 DAO,这些容器不会改变。

如果您从“第一天”开始就使用 SQL 服务器作为后端,而 Access 作为前端,那么 ADO 当然有一些优势,但即使在这些情况下,如果您的访问应用程序是使用DAO,那么我会继续使用 DAO – 即使使用 SQL 服务器。

但是,对于.net开发者,Visual Basic开发者来说,他们很可能使用ADO对象模型磨练了自己的技能,当他们使用MS-access作为开发工具时,他们就可以继续使用他们的“长期”在 MS-access 中编写代码时熟悉 ADO 数据对象模型。

如前所述,我不建议在给定的单个应用程序中混合使用这两种对象模型,因为那样只会让人感到困惑。

编辑:

引用此link: https://docs.microsoft.com/en-us/office/client-developer/access/desktop-database-reference/container-object-dao

每个数据库对象都有一个由内置容器对象组成的容器集合。应用程序可以定义自己的文档类型和相应的容器(仅限 Microsoft Access 数据库引擎数据库);然而,DAO 可能并不总是支持这些对象。

其中一些 Container 对象由 Microsoft Access 数据库引擎定义,而其他对象可能由其他应用程序定义。下面table列出了Microsoft Access数据库引擎定义的每个Container对象的名称及其包含的信息类型.

如果你真的想掌握编程Access的细节,其他答案和在线文档都包含值得理解的好信息。但是,它们通常会排除假设或遗忘的关键细节。在我自己直接回答您的问题之前,请考虑以下几点:

  • 从技术上讲,"object" 模型是一个糟糕的单词选择,因为更合适的术语是 class 模型。通常,对象是 class 的内存中实例。在 运行 期间,确实存在实际对象的层次结构,但有时不引用特定实例(即对象)而是引用整体 class 很有用。我通常对术语非常小心,但特别是在参考其中一些较旧的模型时,文档中使用的名称和术语(坦率地说)草率。这是所有失败术语的免责声明。我会尽力澄清区分对于理解的关键所在。
  • 与 Access 相关的各种对象模型存在冗余。某些冗余可能有充分的理由,但至少某些冗余可能 没有 充分的理由(至少 none 已发布)。相反,各种组件的某些部分是随着时间的推移而发展的成熟产品的结果。不同的信息需要在不同的级别公开,但它不是仅仅使整个模型开放、可访问和一致,而是使用 "as needed" 范式设计的。
    • 两者都存在冗余
      • in name: 具有相同或相似名称的不同class并不相同,但可能提供一组不同的方法和属性来操纵相同的底层实体。这同样适用于集合和枚举的名称。有时它们甚至不操纵相同的底层实体,尽管它们可能提供类似的功能(如 ADO.Recordset 和 DAO.Recordset)
      • 可用性:一些相同的对象通过不同 parent/container 对象的不同集合和属性公开。

It has a container object called "Relationships" and not "Relations". Does this indicate a typo in the documented list of container objects quoted above?

是的,"Relationships" 和 "Relations" 之间的任何差异都只是一个错误,可能没有更深层次的含义。

Where does this container object Forms come from?

这只是一个猜测,但至少是一个直接答案的尝试:

提供容器对象作为相关对象发现的后向引用。当 MS Access creates/loads 通过 DAO 访问数据库时,它显然会为自己的目的添加额外的 Container 对象。 DAO 提供了一个通用的 Containers 集合并允许其他对象添加到它。

尽管 DAO 的目的是简单地访问和表示数据本身,但显然 MS 认为提供一种通过 DAO 对象模型发布(a.k.a.expose)相关对象的方法是有用的。我会认为它就像许多对象的 Parent 属性 一样。没有这样的 Parent 属性,通常没有内置的方法来确定对象与其来源的关系。同样,在复杂的应用程序中,如果没有容器集合,可能没有其他方法可以确定数据库的各种细节。 Albert D. Kallal 已经强调过,DAO 和 Container 对象之间不需要有任何特定的联系。也许容器 classes 和对象确实没有任何有意义的关系,但 MS 显然出于某种原因决定将其添加到 DAO 对象模型中,因此我发现缺少 Kallal 先生的解释。 Access 仍然是具有隐藏方法的专有产品,MS 不会发布所有 API 和 class 的详细信息。老实说,我不相信这是任意的——MS 有他们的理由,即使他们不同意。

What object model does it belong to?

根据文档中描述的内容以及探索 VBA 对象浏览器 中的详细信息并使用一些 VBA 方法,例如 TypeName,等等,看起来 Containers 集合和 Container 对象确实是 DAO 对象模型的一部分。但是,Container 对象(和相关的 Document 对象)本身可以引用 and/or hold DAO 对象模型之外的对象。严格来说,Access Form 的概念在 DAO 之外。 Forms 的实际 classes 和对象是 Access 对象模型的一部分。


更进一步,各种集合不仅仅是简单的 "open forms" 与 "all forms"。虽然他们都return概念实体叫做"forms",但他们甚至return都不是同一类型的运行时间对象。 CurrentDB.Database.Containers(FormContainerIndex) 集合 returns Container 个对象和 Document 个对象(其中 FormContainerIndex 可能等于也可能不等于 2)。 Application.CurrentProject.AllForms 集合 return 个 AccessObject 的实例。 Application.Forms 集合 return 具有特定形式 -class 类型的实际形式对象。

我认为这是一个很好的问题。问题中的文档链接揭示了这会变得多么混乱,因为在 Access 的上下文中,各种概念都混合在一起 。 MS 文档的一个树清楚地表明 DAO 和 ADO 是不同的并且与 Access 分开,但是另一个文档分支将相同的对象放在一个相关数据访问概念的列表中。

不确定这有多不合时宜,但我偶然发现了它,并没有阅读整篇文章,所以我希望上面没有回答这个问题。不过,从粗略的阅读来看,似乎有人遗漏了什么地方。

这是我用来尝试理解 VBA 的怪癖及其结果的一小段代码。先有结果,后有代码。

调用 DumpDBContainers()

当前数据库包含 9 个容器

容器 DataAccessPages 包含 0 个文档
容器数据库包含 3 个文档
容器表单包含 14 个文档
容器模块包含 20 个文档
容器关系包含 4 个文档
容器报告包含 0 个文档
容器脚本包含 22 个文档
容器 SysRel 包含 1 个文档
容器表包含 151 个文档

Public Sub DumpDBContainers()

Dim dbs As Database, Cntr As Container
Dim bNmeOnly As Boolean

Set dbs = CurrentDb()

Debug.Print " "
Debug.Print "Current database contains " & dbs.Containers.count & " containers"
Debug.Print " "

For Each Cntr In dbs.Containers
    Debug.Print "Container " & Cntr.Name & Space(30 - Len(Cntr.Name)) & "contains " & Cntr.Documents.count & " documents"
Next Cntr

End Sub