【问题标题】:How can I have a 1:many table but a 1:1 navigation property?我怎样才能有一个 1:many 表但有一个 1:1 导航属性?
【发布时间】:2012-10-12 16:39:13
【问题描述】:

我有两个实体;让我们称他们为人员和地址。一个人只有一个当前地址 [在此处插入有关政治候选人的笑话],但也有以前的地址,这些地址也存储在 Address 表中。因此,我希望我的数据库表具有 1:many 关系。

然而,在我的实体类中,我不想要 Person 和 Address 之间的 1:many 关系,因为我只对他们的当前地址真正感兴趣. (如果我想了解他们以前的地址,那么我可以直接查看地址表)。所以,我确实想要 Person 对象上的 1:many "Addresses" 属性。相反,我想要一个 1:1 Address 属性,我将其设置为当前地址。

这个可以吗?

【问题讨论】:

  • 将以前的地址存储在单独的表中不是最自然的事情,例如地址历史?他们在同一张桌子上真的很重要吗?
  • 这是一个复杂的表,我不想复制结构(和随之而来的逻辑)。我不认为我的表格设计应该由工具驱动,所以我更愿意像直接创建表格一样构建表格。 (我希望我先使用 DB)。

标签: .net entity-framework ef-code-first entity-framework-5


【解决方案1】:

不可能通过映射来做到这一点,因为 EF 关系紧跟 DB 关系。此外,EF 中的一对一关系基于将外键放在依赖表中的主键上(地址和人员需要具有完全相同的主键值),并且此要求不适用于您期望在表也​​是。

我会尝试这种方法(未测试):

public class MyContext : DbContext {

    public MyContext() {
        ((IObjectContextAdapter)this).ObjectContext.ObjectMaterialized += 
            (sender, e) => {
                var person = e.Person as Person;
                if (person != null) {
                    // Fill the property manually
                    person.Address = this.Addresses.FirstOrDefault(/* some condition */);
                }
    }

    protected override void OnModelCreating(DbModelBuilder builder) {
        // Do not map the propery
        builder.Entity<Person>().Ignore(p => p.Address);

        // other mapping
    }

    public override int SaveChanges() {

        // TODO: here you must have your own change tracking logic
        // for address to know when the address has changed and 
        // new record must be created in the database for old address

        return base.SaveChanges();
    }

    // rest of context class
}

【讨论】:

  • 谢谢+1。您的解决方案令人印象深刻,但对我来说太“吓人”了。我只需要接受我有一个 1:many 属性一个 1:1 属性,正如 Slauma 所建议的那样。
  • @GaryMcGill:即使您不使用它并且它“太吓人”,这也是您的问题“可以完成以及如何完成?”的正确答案。你应该接受拉迪斯拉夫的回答而不是我的回答。
  • @Slauma:OP 的正确答案不一定是解决问题的答案。我的回答主要是解决缺少的功能,它带来了一些缺点,例如地址的手动更改跟踪以及如果您尝试加载 N 个人,还会出现 N+1 查询问题。
【解决方案2】:

不,不能这样做。导航属性表示外键关系,数据库中的 FK 关系表示 one 人的 许多 地址。当前地址是数据库中特定查询的结果,例如 - 取决于“current”的定义方式 - “select top(1) ... order by addresscreationdate descending”查询所有给定人的地址。

我认为可能的解决方案是:

  • 要么在人员表中使用外键CurrentAddressId 创建第二个关系,以引用当前地址。然后你可以在你的Person 类中有一个导航参考CurrentAddress
  • 或者执行查询以使用GetCurrentAddress(Person person) 方法或类似方法加载存储库或服务类中的当前地址。但是你不能在 Person 类上拥有当前地址的导航属性。

【讨论】:

  • 谢谢。我已经使用了您的第一个解决方案。所以我有一个 Addresses 和一个 CurrentAddress 关系。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-01-12
  • 2023-02-02
  • 2018-04-29
  • 1970-01-01
  • 2013-11-13
  • 2020-12-07
  • 2022-12-05
相关资源
最近更新 更多