【问题标题】:How to create a one-to-one relationship where the relationship on both sides is optional如何创建一对一的关系,其中双方的关系都是可选的
【发布时间】:2015-11-26 10:27:00
【问题描述】:

是否可以在两个实体之间创建一个关系,其中每个实体都有一个外键,外键字段也是可选的?我尝试根据以下代码创建表:

public class Museum
{
    public int MuseumId { get; set; }
    public string Name { get; set; }

    [ForeignKey("Curator")]
    public int? CuratorId { get; set; }
    public virtual Curator Curator { get; set; }
}

public class Curator
{
    public int CuratorId { get; set; }
    public string Name { get; set; }

    [ForeignKey("Museum")]
    public int? MuseumId { get; set; }
    public virtual Museum Museum { get; set; }
}

但我收到以下错误:

Curator_Museum_Target: : 多重性在关系“Curator_Museum”中的角色“Curator_Museum_Target”中无效。因为从属角色属性不是关键属性,所以从属角色的多重性的上限必须是'*'。

有没有办法解决这个问题?

【问题讨论】:

    标签: .net sql-server asp.net-mvc entity-framework


    【解决方案1】:

    你不能在数据库中做到这一点。 FK 必须引用关系另一端的 PK。 PK 不能是可选的。例如,您希望在表AB 之间实现的关系将具有以下条件:

    • 如果A.Id 是与B.Id 相关的FK,则B.Id 必须是PK,因此不是可选的
    • 反之亦然,如果 B.Id 是与 A.Id 相关的 FK,则 A.Id 必须是 PK,因此不是可选的

    所以,这不是 EF 的问题,而是你的模型的问题。

    为了模拟这一点,您可以使用桥接表,例如“pseducode”:

    [Table: ABBridge]
    AId not null
    BId not null
    

    因此,如果存在从 AB 的依赖关系形式,反之亦然,您只需在此表中添加一个条目。如果没有这样的关系,则该表中没有字段。 AIdBId 都应该是桥接表的 PK。

    这将是一个多对多的关系。如果您使用的是现代版本的 EF(6.1 或更高版本),您可以通过在两者中使用 Index attribute with IsUnique 使 AIdBId 唯一来将其一对一转换。

    [Index("AIdUniqueIndex", IsUnique = true)]
    public int AId { get; set; }
    [Index("BIdUniqueIndex", IsUnique = true)]
    public int AId { get; set; }
    

    如果您使用的是旧版本,则应使用业务逻辑确保这一点。

    【讨论】:

    • 谢谢。我只假设任何数据结构都可以转换为数据库对象。
    • 如果您认为这回答了您的问题,请将其标记为答案,以便对其他人有用。谢谢。
    【解决方案2】:

    您可以使用 ModelBuilder 的 fluent API 进行配置。

    对于可选的 1:1 关系,代码为:

    ModelBuilder.Entity<Museum>().HasOptional(x => x.Curator).WithOptionalPrincipal(x => x.Museum).WillCascadeOnDelete(true);
    

    正如 JotaBe 所指出的,当将此配置映射到数据库时,EF 不会在两个表中创建外键列。相反,只会为 HasOptional() 子句中定义的一侧创建 FK 列。主/唯一键基表将是配置为 WithOptionalPrincipal() 的一侧。

    对于示例代码,数据库上的 FK 约束将在 Curator 表中创建为 Curator.Museum_Id -> Museum.Id,Museum 作为主/唯一键基表。

    还要注意,上面给出的代码将 cascade delte 配置为“如果博物馆被删除,则删除馆长”。

    【讨论】:

    • 感谢 Georg 的输入,我以前见过这个,但它仍然与我想在我的模型中看到的行为不完全匹配。
    • 如果您在两个实体上都需要一个 FK,您可以对关系建模为 many:many,并按照 JotaBe 的指示添加唯一约束。
    猜你喜欢
    • 1970-01-01
    • 2011-12-02
    • 2020-08-12
    • 2022-10-25
    • 1970-01-01
    • 2016-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多