1

许多企业应用程序都有关系数据库作为对象的后端存储。有些对象是不可变的,有些则不是。

当不可变对象依赖于可变对象时,它应该提供适当的版本。

请参阅:您有Order对象和Customer对象。订单取决于客户。但秩序永远不会改变。订单完成并发货后,客户更改地址。我如何知道哪个地址用于发货?我不想按顺序存储所有信息,因为它会使我的数据库不规范化。

答案是版本控制:订单应取决于具有特定版本的客户。

这是用于共享库(GAC、SxS、不同的 .so 版本等)的想法。

但是如何在数据库中做到这一点?将“版本”字段添加到所有表和任何关系字段?这将增加我的数据库 X2 并使其纠缠。

分离此信息并将其存储在某个地方?

我相信必须有很好的解决方案。你知道任何?

4

2 回答 2

1

正如您已经发现的那样,永远不应该允许不可变数据引用可变数据。答案是使引用的数据不可变。使用版本只是这样做的一个例子,但还有其他方法。

在您的 Order-Customer 示例中,订单不依赖于整个客户——更改客户密码或创建新订单不应以任何方式影响原始订单。因此,您可以从客户身上剔除依赖的部分并使其不可变。这意味着地址是不可变的,但您仍然可以更改客户对其当前地址的引用,因为客户仍然是可变的。

这可以使用关系数据库以多种方式实现。两个明显的:

  • 您可以使地址表只插入(不更新或删除)。这是最简单的方法,但可能会妨碍您的 ORM,并将所有地址保留在数据库中,即使它们与订单无关。

  • 保持地址表可变(允许更新和删除)。然后,每当创建新订单时,您都会创建客户当前地址的副本,并且订单会引用新副本。这应该是对 ORM 最友好的解决方案,但是即使地址永远不会改变,每个订单都会获得自己的地址副本。

于 2012-06-05T17:48:08.453 回答
1

我不太确定我是否理解这个问题。以您的客户和订单为例,您可以

CREATE TABLE address (
  address_id NUMBER PRIMARY KEY,
  street     VARCHAR2(100),
  ...
);

CREATE TABLE customer (
  customer_id NUMBER PRIMARY KEY,
  first_name  VARCHAR2(100),
  ...
  address_id  NUMBER REFERENCES address( address_id )
);

CREATE TABLE orders (
  order_id   NUMBER PRIMARY KEY,
  ...
  customer_id NUMBER REFERENCES customer( customer_id ),
  address_id  NUMBER REFERENCES address( address_id )
);

如果ADDRESS是一级表,则两者ORDERSCUSTOMER可以引用特定的地址。 CUSTOMER可以参考客户的当前地址,ORDERS可以参考订单被切到的地址,该地址可能是客户当时的当前地址,或者可能是他们为之下订单的人的地址(即我下的鲜花订单是我已经在母亲节寄到我妈妈家)。 ADDRESSthen 变为不可变的,因此ADDRESS您无需更新行,只需INSERT使用 new执行ADDRESS_ID并更新CUSTOMER表中的行以指向 new ADDRESS

如果您想跟踪客户地址的历史记录,您只需将表address_id移出customer并放入customer_address具有某种版本相关信息的新映射表中。通常,您会遇到类似这样的情况,您可以在其中指定映射有效的日期范围。

CREATE TABLE customer_address (
  customer_address_id NUMBER PRIMARY KEY,
  customer_id         NUMBER REFERENCES customer( customer_id ),
  address_id          NUMBER REFERENCES address( address_id ),
  valid_from          DATE,
  valid_to            DATE
);
于 2012-06-05T17:41:59.820 回答