10

使用 Entity Framework Code First 4.3.1 时,可以创建具有 1 对 1 多重性的关系。也就是说,关系的每一端都有一个实体。

可以将 1 对 1 关系配置为required-requiredrequired-optional ^。但是,当我在两者之间切换时,我看不出有任何区别:

  • 生成的数据库模式。我的目标是 SQL Server 2008。
  • EF 的运行时行为。

因此,尽管关系被配置为required-required ,但我能够创建没有相应的RequiredDependentAs记录的RequiredPrincipalAs记录。这似乎与HasRequired(...)的文档相矛盾:

配置此实体类型的必需关系。除非指定此关系,否则实体类型的实例将无法保存到数据库中。数据库中的外键将不可为空。

http://msdn.microsoft.com/en-us/library/gg671317

required-required关系实体:

public class RequiredPrincipalA
{
    public int Id { get; set; }
    public virtual RequiredDependentA DependentA { get; set; }
}

public class RequiredDependentA
{
    public int Id { get; set; }
    public virtual RequiredPrincipalA PrincipalA { get; set; }
}

必需的可选关系实体:

public class RequiredPrincipalB
{
    public int Id { get; set; }
    public virtual OptionalDependentB DependentB { get; set; }
}

public class OptionalDependentB
{
    public int Id { get; set; }
    public virtual RequiredPrincipalB PrincipalB { get; set; }
}

DbContext 和模型配置:

public class AppContext : DbContext
{
    public DbSet<RequiredPrincipalA> PrincipalAs { get; set; }
    public DbSet<RequiredDependentA> DependentAs { get; set; }

    public DbSet<RequiredPrincipalB> PrincipalBs { get; set; }
    public DbSet<OptionalDependentB> DependentBs { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<RequiredPrincipalA>()
            .HasRequired(o => o.DependentA)
            .WithRequiredPrincipal(o => o.PrincipalA);

        modelBuilder.Entity<RequiredPrincipalB>()
            .HasOptional(o => o.DependentB)
            .WithRequired(o => o.PrincipalB);
    }
}

测试代码:

Database.SetInitializer(new DropCreateDatabaseAlways<AppContext>());

using (var ctx = new AppContext())
{
    ctx.Database.Initialize(force: false);

    ctx.PrincipalAs.Add(new RequiredPrincipalA());
    ctx.PrincipalBs.Add(new RequiredPrincipalB());

    ctx.SaveChanges();
}

我知道我可以将[Required]数据属性添加到RequiredPrincipalA.DependentARequiredDependentA.PrincipalA的导航属性中。这将导致 EF 验证阻止上述情况。但是,我不想这样做,因为它还会在更新现有实体时验证导航属性是否已填充。这意味着应用程序必须为每次更新预取关系另一端的实体。

为什么仅在更改required-requiredrequired-optional之间的关系时,我看不到 EF 的行为有任何差异?

^请注意,还支持 optional-optional ,但这不构成我的问题的一部分。配置可选-可选关系时,生成的数据库模式和运行时行为存在明显差异。

4

3 回答 3

13

我不知道为什么在这种情况下允许 required-required 但它不能存在于数据库中,因为关系是建立在主键上的。required-required表示如果相关B不存在则无法插入A,如果相关A不存在则无法插入B => A或B都不能插入。

数据库关系始终具有主体和依赖实体 - 主体可以始终存在而没有依赖。

只有当 A 和 B 都映射到同一个表(表拆分)时,才能在 EF 中实现真正的 required-required,因为在这种情况下,它们都是使用单个 insert 命令插入的。

于 2012-06-27T11:10:51.170 回答
5

不是真正的答案,但我要说的比评论更多。但你知道,我写了 900 页的书……这就是我滚动的方式。:)

奇怪的是,我希望流畅的配置与数据注释的行为方式相同,并且很困惑它没有这样做。(我已经用指向该线程的链接 ping Rowan Miller 以获得他的反馈。)我的意思是:在 SaveChanges 期间验证约束。

在数据库方面,我使用 Ladislav。在模型中,EF 使用相关实体的键定义 1:1。但是在数据库中,您不能在两个表中都有 FK,因此只有数据库中的依赖表需要它的 PK 映射到主表中现有 PK 的约束。

最后,如果您不总是处理完整的图表,我理解您不希望 EF 强制执行这种关系的原因。我认为 1:1 关系是 EF 关系映射中最令人困惑的,我总是发现自己不得不回去提醒规则以及事情应该如何工作。

于 2012-06-29T21:08:07.013 回答
0

老问题。但由于 EF6 仍在使用,甚至可用于 .Net 标准,而且这个问题可能是一个真正的麻烦,我认为值得一提的是我在其他答案中找不到的东西。

确实,两者都HasRequired - WithRequiredPrincipal产生HasOptional - WithRequired相同的数据库模式和相同的运行时行为。也就是说,使用这两种映射都可以保存没有依赖实体的主体,并在以后删除依赖实体。这么多HasRequired

但是有一种方法可以让 EF在创建实体时验证所需的关系,即简单地添加一个[Required]属性:

public class RequiredPrincipalA
{
    public int Id { get; set; }

    [Required] // <== here
    public virtual RequiredDependentA DependentA { get; set; }
}

public class RequiredDependentA
{
    public int Id { get; set; }
    public virtual RequiredPrincipalA PrincipalA { get; set; }
}

如前所述,仅在创建实体时。仍然可以设置RequiredPrincipalA.RequiredDependentA = null并保存成功。但我认为,幸运的是,在代码中发生这种情况的可能性远低于忘记设置所需的依赖项。

于 2021-01-15T22:15:45.603 回答