代码之家  ›  专栏  ›  技术社区  ›  Mawg says reinstate Monica

主/细节是如何工作的?[已关闭]

  •  -2
  • Mawg says reinstate Monica  · 技术社区  · 13 年前

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

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

    这个 customers 数据库中的表具有:

    • 一个自动递增的整数 customer_id 作为主键
    • 客户名称的文本字段
    • 联系人详细信息的文本字段

    orders 表具有:

    • 整数 客户id 它是一个外键,引用 客户 桌子
    • 其他一些东西,比如对一堆物品编号的引用
    • 整数 order_value 存储订单的现金价值

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

    到目前为止,这么好?还是我已经错过了什么?

    现在,教程说我必须设置数据源的MasterSource,它对应于显示 订单 表是与 客户 表和 MasterFields 在这种情况下 客户id .

    还有别的吗?例如,我应该设置 Detailfields 对应于 客户 表到 客户id ?

    我应该使用这些属性吗,或者 a paramaterized query ?

    好的,在这一点上,我们已经遵循了经典教程,可以滚动浏览 客户 DB网格中显示的当前客户的所有订单 订单 数据库网格。当用户单击 客户 DB网格我必须关闭();然后打开();这个 订单 查询以刷新其相应的DB网格。

    然而,这些教程似乎总是假设一个静态数据库,其中包含从未更改的现有内容。

    当我问另一个问题时,我举了一个例子,我使用命令 INSERT INTO orders... 有人告诉我这是件坏事,我应该:

    • 订单查询.Append();
    • OrdersQuery.FieldByName('customer_id'):=[某些值]';
    • OrdersQuery.FieldByName('item_numbers'):=[某些值]';
    • OrdersQuery.FieldByName('order_value'):=[某些值]';
    • 订单查询.Post();

    这是正确的吗?

    我之所以这么问,是因为在我看来,命令会放入数据 在里面 查询应该只接受它 出来 ,但我可以看到,命令没有通过数据源的查询链接到DB网格。

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

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

    如果必须使用查询,如何实现SQL UPDATE DROP ?

    最后,我可以建立主/细节/细节关系吗?

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

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

    1 回复  |  直到 13 年前
        1
  •  2
  •   Warren P    13 年前

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

    当有些人说“细节大师”时,他们不会一直走到兔子洞里。你的问题表明你确实想。我想分享一些我认为有帮助的事情,但我认为没有人能真正完全回答你的问题。

    1. 对于任何两个数据集,出于某些人的目的,主细节的最小实现只不过是当主表中当前选定的行发生更改时触发的事件处理程序。然后,该行用于筛选明细表数据集中的行,以便只有与主行主键匹配的行可见。如果配置得当,在Delphi的VCL中的大多数类似TTable的对象中都可以实现这一点,但如果您愿意编写一些事件处理程序和过滤数据,即使是不明确支持主/细节配置的数据集也可以以这种方式运行。

    2. 在我的一位前雇主那里,有人发明了一个Master Detail控制器组件,它与Delphi的ADO组件的一个鲜为人知的变体Kamiak一起,它具有一些特性,这些特性是那些只熟悉BDE TTable时代主细节概念的人所没有想到的。这是一项非常巧妙的工作,它具有以下特点:

      • 您可以创建一个ADO记录集并将其保存在内存中,然后作为一个批处理,一次写入一系列细节行,如果并且仅当主行要存储到磁盘时。
      • 您可以将这些主细节关系嵌套到几乎任意的深度,因此您可以拥有主、细节和子细节记录。批量更新用于更新,以回答您的问题。要处理更新,您需要滚动自己的ORM或记录集层,或者使用预先构建的缓存/记录集层。有很多选项,从ADO到Delphi的各种类似ORM的组件,甚至包括客户端数据集或带有数据泵的公文包模型。
      • 您可以修改数据并将其发布到内存中的暂存区域,然后一次刷新所有的主行和细节行,或者放弃它们。这使得持久性管理几乎达到了对象关系级别。

    尽管上面的滚动你自己的ORM方法看起来很可爱,但它也有黑暗的一面。系统中的奇怪错误导致我再也不想使用这种方法了。我不想夸大其词,但我能谦虚地说,有一件事是在细节大师的兔子洞里走得太远吗?不要去那里。或者,如果你这样做了,请意识到你真的在构建一个迷你ORM,并准备好做这项工作,其中应该包括一组非常扎实的单元测试和集成测试。即便如此,也要注意,你可能会发现一些非常奇怪的角落案例,并可能发现一些真正邪恶的bug潜伏在你美丽的ORM/MasterDetail中。

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

    在BDE/dBase/platt文件时代,我本可以实现为“主细节”,现在我只需实现为主行的查询和第二个细节行的查询,当主行更改时,我会刷新细节行查询,并且不使用 MasterSource 或TTable对象中的相关Master/Detail属性。