如何实现具有 "Is Current" 需求的一对多关系

How to implement a one-to-many relationship with an "Is Current" requirement

设计数据库,两个table之间存在关系,JobDocument。一个 Job 可以有多个 Documents,但是其中一个(并且只有一个)Documents 需要标记为 IsCurrent。这并不总是与 Job 关联的最新 Document

在结构上,我可以看到两种方法。

首先是在Job中添加DocumentId列,在Document中添加JobId列。这会起作用,但会创建一个循环引用:当导入 Entity Framework 时,您会遇到 Job 同时具有 DocumentDocuments 集合的特殊情况。同样,Document 有一个 Job 和一个 Jobs 集合。

二是在Documenttable上加一个IsCurrent位标志。这会起作用,但从逻辑上讲,一个作业可以有多个 IsCurrent Documents,这是不允许的。

问题:

1) 我认为没有 "third way" 摆脱这种困境是对的吗?

2) 假设不是,哪个更好,为什么?我赞成第二种解决方案,因为它看起来更简洁,而且我们可以通过业务逻辑强制执行单个 IsCurrent。我的同事喜欢前一种解决方案,因为它会导致更简单的 C# 代码和对象引用 - 如果我们重命名外键,它应该避免 Job/Jobs 造成的混淆。

只是为了第三种方式(也是为了好玩):考虑在作业的文档中使用 not a bit,但 int 等于 max + 1。

然后在 {job FK, said int} 上创建一个唯一索引。

您可以:

  • 通过更新 int 改变电流,
  • 通过搜索最大值获取电流
  • 防止因为唯一索引而出现多个当前。
  • 使用 min - 1 为所述整数创建一个新的非当前文档。

这不是最简单的实现方式。

是的,还有第三种方法可以摆脱这种困境。您需要一个支持 SQL 的 CREATE ASSERTION 的 DBMS(当然 正确 支持它)。使用这样的 DBMS,您可以声明适用于您的情况的任何数据规则,您的 DBMS 将为您执行该规则。

不幸的是,在 SQL 世界 * 中 * 不存在这样的 DBMS。在 SQL 世界之外,还有这样的引擎。断言是我的木马,我自己写了一个。如果您有兴趣,Google 搜索应该会很快找到它。

如果你的后端是SQL服务器,你可以创建一个filtered index来确保每个job最多有一个当前文档:

CREATE UNIQUE INDEX IX_Documents_Current
    ON Documents (JobId) where IsCurrent=1

这样一来,它就不会只是在业务级别强制执行,而是在数据库内部强制执行。