【问题标题】:EF 1 to 1..* relationshipEF 1 到 1..* 关系
【发布时间】:2017-06-13 10:19:22
【问题描述】:

有没有办法在实体框架中创建一对一或多关系?我已经看到很多例子显示了 1 到 0..* 的关系,但我想确保在给定的例子中 Foo 只有在它至少有一个 Bar 时才能存在。

class Foo
{
   List<Bar> Bars { get; set; }
}

class Bar
{
    public Foo Foo { get; set; }
}

我发现这不是通过 SQL 轻松实现的,因为我希望在 Foo 表而不是 Bar 表中使用一种 NOT NULL,但是 Entity Framework 可以处理这个吗?

我意识到我问错了问题,因为我实际上是在寻找 0..1 到 1..* 的关系,这是截然不同的。 This 是我想问的问题。

【问题讨论】:

    标签: entity-framework ef-code-first


    【解决方案1】:

    据我所知,在任何 SQL 数据库中都不可能存在真正的 1 对 1 关系。虽然集合论允许 1 比 1,但在实践中,这很难实现。

    这基本上是先有鸡还是先有蛋的情况。你不能创建 Foo 因为你没有 Bar,你不能创建 Bar 因为还没有 Foo。创建 1 到 1 所需的约束基本上会阻止您插入任何实际行。

    现在,您可以禁用约束,插入数据,然后重新启用它们,但这是一个 hacky kludge,它真正违背了最初设置约束的目的。

    所以只需接受 1 到 0..* 并继续前进。

    【讨论】:

      【解决方案2】:

      尽可能接近是这样的:

      class Foo
      {
          List<Bar> Bars { get; set; }
      
          [Required]
          public int PrimaryBarId { get; set; }
          public Bar PrimaryBar { get; set; }
      }
      
      class Bar
      {
          public Foo Foo { get; set; }
      }
      

      但注意数据库不会强制执行

      aFoo.PrimaryBar.FooId == aFoo.Id

      由于循环 FK,这种模型很难更新。

      【讨论】:

        【解决方案3】:

        在下面的示例中讨论了实施这种解决方案的困难和可能性。


        一对一映射

        一对一映射(当需要双方时)也是一件棘手的事情。

        让我们想象一下如何用外键表示它。同样,People 中的 CarId 引用 Car 中的 CarId,Car 中的 PersonId 引用 People 中的 PersonId

        现在如果您想插入汽车记录会发生什么?为了成功,必须在此汽车记录中指定PersonId,因为它是必需的。要使这个PersonId 有效,People 中的对应记录必须存在。好的,让我们继续插入人员记录。但要成功,有效的CarId 必须在人员记录中——但那辆车还没有插入!不可能,因为我们必须先插入被推荐人的记录。但是我们不能插入引用的人记录,因为它引用回汽车记录,所以必须先插入(外键接收:))。

        所以这也不能用“合乎逻辑”的方式来表示。同样,您必须删除其中一个外键。你放弃哪一个取决于你。有外键的一侧称为“从属”,没有外键的一侧称为“主”。同样,为了确保依赖项的唯一性,PK 必须是 FK,因此不支持添加 FK 列并将其导入您的模型。

        所以这是配置:

        public class CarEntityTypeConfiguration : EntityTypeConfiguration<Car>
        {
          public CarEntityTypeConfiguration()
          {
            this.HasRequired(c => c.Person).WithRequiredDependent(p => p.Car);
            this.HasKey(c => c.PersonId);
          }
        }
        

        现在你真的应该明白它的逻辑了 :) 请记住,你也可以选择另一边,只是要小心使用 WithRequired 的 Dependent/Principal 版本(你仍然必须在汽车)。

        public class PersonEntityTypeConfiguration : EntityTypeConfiguration<Person>
        {
          public PersonEntityTypeConfiguration()
          {
            this.HasRequired(p => p.Car).WithRequiredPrincipal(c => c.Person);
          }
        }
        

        如果您检查数据库架构,您会发现它与一对一或零解决方案的情况完全相同。那是因为这不是由架构强制执行的,而是由 EF 本身强制执行的。再说一次,要小心:)

        【讨论】:

          猜你喜欢
          • 2021-11-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-26
          • 2012-12-10
          • 1970-01-01
          相关资源
          最近更新 更多