1 to 1 relationship

本文关键字:relationship to | 更新日期: 2023-09-27 18:00:36

工人只能有一辆车,而车辆一次只能属于一名工人。我知道有三种可能的实现:
1.

Vehicle(Id, Number)
Worker(Id, Name, VehicleId)
--> This allows two workers have the same vehicle.

2.

Worker(Id, Name)
Vehicle(Id, Number, WorkerId)
--> This allows worker to have two vehicles.

3.

   Worker(Id, Name)
   Vehicle(Id, Number)
   WorkersVehicles(Id, VehicleId, WorkerId)
    --> This allows each worker to have many vehicles and each vehicle to belong to many workers.

以上都无法描述所需的1:1关系。

我如何在数据库和实体框架中描述这种1:1的关系?

1 to 1 relationship

定义一个仅通过约束强制执行1:1关系的数据模型是不可能的,因为这需要一个循环引用,这意味着在另一边存在之前,您永远无法插入关系的一边。

虽然可以通过欺骗(删除约束,使用RDBMS特定的命令,如Oracle的延迟约束)来绕过这一点,但在传统意义上是不可能做到的。你能得到的最接近的是1:0..1

以下是代表Worker:Vehicle:的各种组合的模型

0..1:1

Worker (ID, VehicleID unique constraint)
Vehicle (ID)

1:0..1

Worker (ID)
Vehicle (ID, WorkerID unique constraint)

0..1:0..1

Worker (ID)
Vehicle (ID)
WorkerVehicle (WorkerID, VehicleID) <-- primary key on one column, 
                                        unique constraint on the other

不幸的是,由于EF不支持唯一约束(或者更确切地说,它不识别或强制执行这些约束),您最终总是会得到关系另一端的集合,而不是单个实体。

您可能需要使用一个唯一的约束,即员工必须具有唯一的VehicleId

根据这篇SO文章,EF似乎不直接支持唯一约束。我如何向ADO.NET实体添加约束?

正如@Adam所描述的,您需要使FK唯一以强制一对一关系,因为EF不支持唯一约束,所以在EF中实现这一点的唯一方法是:

Worker(ID)
Vehicle(ID) <-- PK and FK to worker

将FK置于PK将强制执行唯一性。解决方法是使用:

Worker(ID)
Vehicle(ID, WorkerID) <-- WorkerID is FK with unique constraint in the database

一旦将其映射到EDMX,您将从Worker中删除Vehicles导航属性。若将一辆车分配给两个工人,数据库将抛出异常。这种解决方法的缺点是,您无法从工人那里访问车辆(您没有导航属性)。

无论如何,一对一关系是罕见的——它应该主要用于"is-a",而很少用于"has-a"场景。在某些情况下,我认为在应用程序逻辑中使用一对多而不是一对一和控制验证是合理的。如果未来需求发生变化,向主体添加新的相关实体将只是更改验证,而不是更改一半的应用程序。你可以决定这是否是你的情况。

这类事情既可以在数据库中处理,也可以在代码中处理。如果你在代码中这样做,那么在尝试保留你的对象之前,只需创建一个规则,检查车辆是否属于另一名工人。如果是,则抛出异常。如果您也选择在数据库中添加规则,则应在包含外键的表上的触发器中执行,该触发器将再次检查车辆是否属于另一个工作人员,如果属于,则会引发错误。实体框架不应该用于处理业务逻辑。