(请注意,这是使用 EF 6.4.4。)
只要您不想要外键属性,指定起来就相当简单:
modelBuilder
.Entity<Order>()
.HasOptional(o => o.Quotation)
.WithOptionalPrincipal(q => q.Order);
modelBuilder
.Entity<Quotation>()
.HasOptional(q => q.Order)
.WithOptionalDependent(o => o.Quotation);
WithOptionalPrincipal
请注意这里和的用法WithOptionalDependent
。这应该在依赖端为您提供一个外键列(示例中的引号),但没有外键属性。如果您想要另一边的外键,请切换“依赖”和“主体”。
(请注意,没有必要同时拥有以上两个定义;WithOptionalDependent
这意味着另一方是主体,反之亦然,因此如果需要,您可以只使用其中一个,但我发现指定双方的关系有助于防止错误通过双重声明;任何冲突都会导致模型错误,让你知道你错过了一些东西。)
虽然外键列上有索引,但该索引没有唯一约束。虽然可以添加自己的唯一约束(这需要Key IS NOT NULL
过滤器),但它似乎不起作用,并且在某些情况下更新关系时会出现异常。我认为这与 EF 将在单独的查询中执行其更新的“交换问题”有关,因此强制唯一性将阻止 EF 分两步“移动”密钥。
EF 似乎在内部处理关联本身,没有唯一的 DB 约束:
- 在任一方面,分配已使用的引用会导致引用的其他用法被自动删除。(所以如果你打开上下文的时候已经是A1 <=> B1,然后你写A1 => B2,那么A1 <=> B1被去掉,A1 <=> B2被添加,不管哪边轮到你了。)
- 如果您尝试通过多次分配相同的引用来创建重复键,EF 将抛出一个异常,说“违反多重约束”。(所以在相同的上下文中,您同时编写了 A1 => B1 和 A2 => B1,或者一些类似的冲突映射。)
- 如果您手动更新数据库以创建重复键的情况,当 EF 遇到这种情况时,它会抛出一个异常,说“发生关系多重性约束违规......这是一个不可恢复的错误。”
在 EF6 中似乎不可能将属性映射到外键列(至少使用 Fluent API)。尝试这样做会导致非唯一的列名异常,因为它尝试分别对属性和关联使用相同的名称。
另请注意,拥有两个外键(即:两边各一个)在技术上是不正确的。这样的安排实际上是两个0..1 到 0..1 的关联,因为没有什么可以说两端的键应该匹配。如果您通过 UI 和/或某种数据库约束以其他方式强制执行关系,这可能会起作用。
我还注意到,对于 0..1 到 0..1 关联究竟是什么,可能存在误解/误解。这意味着,根据我的理解以及 EF 似乎也考虑它的方式,它是一个 1 对 1 的关联,双方都是可选的。因此,您可以在任何一方拥有没有关系的对象。(而 1 到 0..1 的关联,一侧的对象可以在没有关系的情况下存在,但另一侧的对象总是需要一个对象来关联。)
但是 0..1 到 0..1 并不意味着您可以让关联在一个方向而不是另一个方向上传播。如果 A1 => B1,则 B1 => A1 (A1 <=> B1)。如果不使 A1 与 B1 相关,则无法将 B1 分配给 A1。这就是为什么这个关联可以只使用一个外键。我认为有些人可能试图建立一个不正确的关联(A1 与 B1 相关,但 B1 与 A1 无关)。但这实际上不是一个关联,而是两个 0..1 到 0..1 关联。