Master / Detail如何工作?

时间:2013-03-13 01:54:50

标签: delphi master-detail

我找到了一些教程,但他们仍然给我留下了问题。

我们来看一个2个表的经典例子,一个用于客户详细信息,另一个用于订单详细信息。

数据库中的customers表具有:

  • 自动增量整数customer_id作为主键
  • 客户名称的文本字段
  • 联系方式的文字字段

orders表格包含:

  • 一个整数customer_id,它是引用customers
  • 的外键
  • 其他一些东西,例如对一堆物品号的引用
  • 用于存储订单现金价值的整数order_value

我需要两个数据集组件,两个查询和一个连接。

到目前为止,这么好吗?或者我已经错过了什么?

现在,教程说我必须设置数据源的MasterSource,它对应于DB网格,显示orders表是与customers表对应的数据源和MasterFields,在本例中为customer_id

还有别的吗?例如,我应该将与Detailfields表对应的数据源查询的customers设置为customer_id吗?

我应该使用这些属性,还是a paramaterized query

好的,此时,我们已经按照经典教程进行操作,可以滚动customers数据库网格,查看orders数据库网格中显示的当前客户的所有订单。当用户单击customers数据库网格时,我必须关闭();然后打开(); orders查询以刷新其对应的数据库网格。

然而,这些教程似乎总是假定一个静态数据库,其中包含永远不会改变的现有内容。

当我问一个问题时,我给出了一个例子,我使用了一个命令来INSERT INTO orders...并被告知那是一件坏事,我应该:

  • OrdersQuery.Append();
  • OrdersQuery.FieldByName('customer_id'):= [some value]';
  • OrdersQuery.FieldByName('item_numbers'):= [some value]';
  • OrdersQuery.FieldByName('order_value'):= [some value]';
  • OrdersQuery.Post();

这是对的吗?

我问,因为在我看来,命令将数据放入,查询应该只将输出,但我可以看到命令没有通过数据源的查询链接到数据库网格。

这是一个选择问题,还是必须使用查询?

如果是这样,似乎我甚至不能使用简单的SQL函数,例如SUM,MIN<查询中的AVG,MAX必须将它们移动到我的代码中。

如果我必须使用该查询,我该如何实现SQL UPDATEDROP

最后,我可以拥有Master / Detail / Detail关系吗?

假设我想要一个第三个数据库网格,它显示了客户所有订单的总数和平均值。它从orders表中获取数据(但不能使用SUM和AVG),每次用户选择不同的客户时都会更新,从而提供主/明细/详细关系。我只是将其设置为两个主/细节关系? I.E,DB网格,数据源,总订单和平均订单的查询仅指orders,并且没有customers的引用,即使它确实使用customer_id

提前感谢您的任何帮助和澄清。我希望这个问题将来会成为其他人的参考(所以,随时编辑它)。

1 个答案:

答案 0 :(得分:1)

TLDR:在SQL世界中,Master / Detail是一种古老的。

当有人说“Master Detail”时,他们不会一直走到兔子洞口。你的问题表明你确实想要。我想分享一些我认为有用的东西,但我不认为任何人都可以完全回答你的问题。

  1. 对于任何两个数据集,出于某些人的目的,主细节的最小实现只不过是当主表中当前选定的行发生更改时触发的事件处理程序。然后,此行用于过滤详细信息表数据集中的行,以便只显示与主行的主键匹配的行。如果你在Delphi的VCL中的大多数类似TTable的对象中正确配置它,那么这是为你完成的,但是如果你愿意写的话,即使没有明确支持主/详细配置的数据集也能以这种方式运行。一些事件处理程序和过滤数据。

  2. 在我以前的一个雇主中,一个人发明了一个Master Detail控制器组件,它与一个名为Kamiak的Delphi的ADO组件的一个鲜为人知的变体,它有一些属性,只有那些人熟悉BDE-TTable时代的主要细节概念是不可预料的。这是一项非常聪明的工作,它具有以下特点:

    • 您可以创建一个ADO记录集并将其保存在内存中,然后作为批处理,一次性写入一系列详细信息行,当且仅当主行要存储到磁盘时。
    • 您可以将这些主 - 细节关系嵌套到几乎任意深度,因此您可以拥有主要,详细和子细节记录。批量更新用于更新,以回答您问题的这一部分。要处理更新,您需要滚动自己的ORM或Recordset层,或使用预先构建的缓存/记录集层。从ADO到Delphi的各种类似ORM的组件,甚至是涉及客户端数据集或带有数据泵的公文包模型,都有很多选择。
    • 您可以修改数据并将数据发布到内存中的暂存区域,并立即刷新所有主行和详细行,或放弃它们。这允许几乎对象关系级别的持久性管理。
  3. 像上面的滚动你自己的ORM方法一样可爱,并不是没有它的黑暗面。系统中的奇怪错误使我永远不想再次使用这种方法。我不想夸大事情,但是我可以谦卑地暗示,在主人细节兔洞中走得太远了吗?不要去那里。或者,如果你这样做,意识到你真的在构建一个迷你ORM,并准备好做这项工作,其中应包括一套非常可靠的单元测试和集成测试。即便如此,请注意你可能会发现一些非常奇怪的角落案例,并且可能会发现一些真正邪恶的错误潜伏在你美丽的ORM / MasterDetail中。

    就插入而言,当然取决于您是构建者还是用户。如果你不害怕SQL,那么满足于在VCL中构建任何Table类并且永远不想用SQL弄脏他们的人的人会认为你的方法是错误的。我不知道那个人将如何处理自动分配的身份主键。我将一个人记录存储在一个表中,我立即需要获取该人新分配的ID,这是一个整数,我现在将使用该整数主键,将我的详细行与主行关联,详细信息行,因此引用主行的ID整数,作为外键,因为我的SQL数据库构造良好,具有参照完整性约束,并且因为我事先考虑了所有这些并且不想这样做一遍又一遍,我最终从这里开始,构建一个对象关系映射框架。我希望你能看到你的许多问题如何有许多可能的答案,答案导致数百或数百万种可能的方法,而且没有一个正确的答案。我碰巧是ORM中的一个不相信者,而且我觉得在这个疯狂的火车上下车的安全之地就在你上车之前。我手工编写我的SQL代码,然后手工编写我的业务对象代码,而且我不使用任何花哨的Master Detail或ORM东西。但是,您可以选择按自己喜欢的方式进行操作。

    我将在BDE / dBase /平面文件时代实现“主要细节”,我现在只是作为主行的查询实现,第二次查询细节行,当主行更改时,我刷新了详细信息行查询,并且我根本不使用TTable对象中的MasterSource或相关的Master / Detail属性。