简体   繁体   English

数据库1:1关系外键

[英]Database 1:1 relationship foreign key

Let's suppose I have an CustomerOrder table and a RentalEquipment table. 假设我有一个CustomerOrder表和一个RentalEquipment表。

A customer is able to rent one of the RentalEquipment and that unique rental equipment is recorded within the CustomerOrder . 客户可以租用其中一个RentalEquipment并在CustomerOrder记录该独特的租赁设备。

Since the relationship is 1:1 (for a customer to rent 2 equipments, 2 orders must be made), which of both should contain the foreign key? 由于关系是1:1 (客户要租2台设备,必须订2份),哪两个都应该包含外键?

Consider the following: 考虑以下:

  1. A customer may return a rental equipment, so it will be available to another customer's order anytime in the future. 客户可以退回租赁设备,以便将来随时可以使用其他客户的订单。

What I would do is create a separate table for the relationship between customer orders and rental equipment - let's call it CustomerRental and this would have two columns for each foreign key and a composite primary key made up of each key. 我要做的是为客户订单和租赁设备之间的关系创建一个单独的表 - 让我们称之为CustomerRental ,这将为每个外键提供两列,并为每个键组成一个复合主键。 This way each row for a customer or order could be modified independently without worrying about breaking the relationship(s) between them. 这样,客户或订单的每一行都可以独立修改,而不必担心破坏它们之间的关系。

In the case of a return I would suggest creating another table to capture this idea let's call it CustomerRentalStatus which maps many:1 to RentalStatus . 在返回的情况下,我建议创建另一个表来捕获这个想法让我们称之为CustomerRentalStatus ,它将许多:1映射到RentalStatus Programmatically what this lets you do is validate the rental status of the order eg "Received", "Dispatched", "Delivered", "Returned" and you can have a modified date column to check when the status was last updated. 以编程方式,这可以验证订单的租赁状态,例如“已接收”,“已发送”,“已下达”,“已退回”,您可以使用修改日期列来检查状态上次更新的时间。

Of course you might not want to normalize your solution this far yet depending on the needs of your application (yagni) in which case you could just have a column in the Orders table to capture the status of the order 当然,根据应用程序的需要(yagni),您可能不希望规范化您的解决方案,在这种情况下,您可以在Orders表中有一列来捕获Orders的状态

Well, consider this. 好吧,考虑一下。 Does a RentalEquipment contain a CustomerOrder, or does a CustomerOrder contain a RentalEquipment? RentalEquipment是否包含CustomerOrder,或者CustomerOrder是否包含RentalEquipment?

My guess is that it's the latter, unless you have a very odd system. 我的猜测是后者,除非你有一个非常奇怪的系统。

Given that, a CustomerOrder should contain a reference to the RentalEquipment it contains. 鉴于此,CustomerOrder应包含对其包含的RentalEquipment的引用。 You can have a status flag on the CustomerOrder indicating whether the order is still open, or the RentalEquipment has been returned. 您可以在CustomerOrder上有一个状态标志,指示订单是否仍处于打开状态,或者是否已返回RentalEquipment。

This also makes sense if you want to track the order history of a given RentalEquipment. 如果您想跟踪给定RentalEquipment的订单历史记录,这也是有意义的。

If it's a foreign key in CustomerOrder, you can look through your CustomerOrders to find the history. 如果它是CustomerOrder中的外键,您可以查看CustomerOrders以查找历史记录。 If you put the relationship in RentalEquipment, you'll only have information about the CurrentOrder. 如果您将关系放在RentalEquipment中,那么您将只获得有关CurrentOrder的信息。 Also, when the customer returns it, you'll have to update the RentalEquipment record and set the FK to null. 此外,当客户返回它时,您必须更新RentalEquipment记录并将FK设置为​​null。 Messy. 凌乱。

This is not actually 1:1. 这实际上不是1:1。

Same piece of equipment can be rented to multiple customers and same customer can rent multiple pieces of equipment, as long as that's done at different times... 同一件设备可以租给多个客户,同一个客户可以租用多件设备,只要在不同的时间完成......

  1. So its actually M:N, over the lifetime of the database . 所以它实际上是M:N,在数据库的生命周期内
  2. However, it is 1:1 within a particular period of time . 但是,在特定时间段内它是1:1。

So you need to represent the (1) through a junction table and find a way to enforce the (2). 因此,您需要通过联结表来表示(1)并找到强制执行(2)的方法。

Consider the following model: 考虑以下模型:

在此输入图像描述

[From, To] is the time period of renting. [From, To]是租赁的时间段。

  • The UNIQUE constraint {CustomerId, From} ensures a customer cannot start renting (same or different equipment) twice at the same time. UNIQUE约束{CustomerId, From}确保客户无法同时开始租用(相同或不同的设备)两次。
  • The UNIQUE constraint {RentalEquipmentId, From} ensures a piece of equipment cannot start to be rented (to same or different customer) twice at the same time. UNIQUE约束{RentalEquipmentId, From}确保一件设备无法同时开始(相同或不同的客户)租用两次。

Unfortunately, both constraints work only on moments in time and neither guarantees there will be no overlaps of time periods (in other words: they don't take To into account). 不幸的是,限制在时间的时刻只工作,不担保不会有时间的重叠(换句话说:他们没有考虑To考虑)。 You'll need to find a way to prevent the overlap of time period [From, To] for any given CustomerId (and the same for any given RentalEquipmentId ). 您需要找到一种方法来防止任何给定CustomerId的时间段[From, To]重叠(对于任何给定的RentalEquipmentId相同的)。

If you are lucky, your DBMS can do that for you (see exclusion constraint under PostgreSQL). 如果运气好,您的DBMS可以为您做到这一点(请参阅PostgreSQL下的排除约束 )。 Otherwise, you can enforce it with a trigger (but be careful to lock properly, to avoid race conditions). 否则,您可以使用触发器强制执行(但要小心锁定,以避免竞争条件)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM