简体   繁体   English

Entity Framework Code First一对一必需关系

[英]Entity Framework Code First One-to-One Required-Required Relationship

When using Entity Framework Code First 4.3.1 it is possible to create relationships with a multiplicity of 1-to-1.使用 Entity Framework Code First 4.3.1 时,可以创建具有 1 对 1 多重性的关系。 That is, one entity on each end of the relationship.也就是说,关系的每一端都有一个实体。

It is possible to configure 1-to-1 relationships to be required-required or required-optional ^.可以将 1 对 1 关系配置为必需-必需必需-可选^。 However, when I switch between the two I do not see any differences in:但是,当我在两者之间切换时,我看不出有任何区别:

  • The database schema generated.生成的数据库模式。 I am targeting SQL Server 2008.我的目标是 SQL Server 2008。
  • The runtime behaviour of EF. EF 的运行时行为。

As such, I am able to create a RequiredPrincipalAs record without a corresponding RequiredDependentAs record, despite the relationship being configured as required-required .因此,尽管关系被配置为required-required ,但我能够创建没有相应RequiredDependentAs记录的RequiredPrincipalAs记录。 This seems to contradict the documentation for HasRequired(...) :这似乎与HasRequired(...)的文档相矛盾:

Configures a required relationship from this entity type.配置此实体类型的必需关系。 Instances of the entity type will not be able to be saved to the database unless this relationship is specified.除非指定此关系,否则实体类型的实例将无法保存到数据库中。 The foreign key in the database will be non-nullable.数据库中的外键将不可为空。

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

The required-required relationship entities: 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; }
}

The required-optional relationship entities:必需-可选关系实体:

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; }
}

The DbContext and model configuration: 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);
    }
}

The test code:测试代码:

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();
}

I am aware I could add a [Required] data attribute to the navigation properties of RequiredPrincipalA.DependentA and RequiredDependentA.PrincipalA .我知道我可以将[Required]数据属性添加到RequiredPrincipalA.DependentARequiredDependentA.PrincipalA的导航属性。 This would cause EF validation to prevent the scenario above.这将导致 EF 验证阻止上述情况。 However, I do not want to do this because it also validates the navigation property is populated when updating an existing entity.但是,我不想这样做,因为它还会验证在更新现有实体时填充了导航属性。 This means the application has to pre-fetch the entity at the other end of the relationship for every update.这意味着应用程序必须为每次更新预取关系另一端的实体。

Why do I not see any difference in the behaviour of EF just when changing a relationship between required-required and required-optional ?为什么我在更改required-requiredrequired-optional之间的关系时看不到 EF 的行为有任何差异?

^ Note that optional-optional is also supported but this doesn't form part of my question. ^请注意,也支持 optional-optional 但这不构成我的问题的一部分。 There are obvious differences in the generated database schema and runtime behaviour when an optional-optional relationship is configured.配置可选-可选关系时,生成的数据库模式和运行时行为存在明显差异。

I don't know why required-required is allowed for this case but it cannot exist in the database because relation is build on primary keys.我不知道为什么在这种情况下允许 required-required 但它不能存在于数据库中,因为关系是建立在主键上的。 Required-required means that A cannot be inserted if related B doesn't exist and B cannot be inserted if related A doesn't exist => neither A or B can be inserted. Required-required 表示如果相关 B 不存在则无法插入 A,如果相关 A 不存在则无法插入 B => 既不能插入 A 也不能插入 B。

Database relation has always principal and dependent entity - principal can always exist without dependent.数据库关系始终具有主体和依赖实体 - 主体始终可以在没有依赖的情况下存在。

Real required-required in EF can be achieved only when both A and B are mapped to the same table ( table splitting ) because in such case they are both inserted with single insert command.只有当 A 和 B 都映射到同一个表( 表拆分)时,才能在 EF 中实现真正的 required-required,因为在这种情况下,它们都是使用单个插入命令插入的。

Not really an answer but I have more to say than will fit in comments.不是真正的答案,但我要说的比评论要多。 But you know, I write 900 page books...it's just how I roll.但是你知道,我写了 900 页的书……这就是我的工作方式。 :) :)

Oddly I would expect the fluent configuration to behave the same way as the data annotation and am confused that it's not doing it.奇怪的是,我希望流畅的配置与数据注释的行为方式相同,但我很困惑它没有这样做。 (I've pinged Rowan Miller with a link to this thread to get his feedback.) And the behavior I mean is: validating the constraint during SaveChanges. (我已经通过此线程的链接向 Rowan Miller 发送了 ping,以获取他的反馈。)我的意思是:在 SaveChanges 期间验证约束。

On the database side, I'm with Ladislav.In the model, EF defines the 1:1 using the keys of the related entities.在数据库方面,我与 Ladislav 合作。在模型中,EF 使用相关实体的键定义 1:1。 But in the database, you can't have FKs in both tables, so only the dependent table in the database will require that constraint that it's PK maps to an existing PK in the principal table.但是在数据库中,您不能在两个表中都有 FK,因此只有数据库中的从属表需要将其 PK 映射到主表中现有 PK 的约束。

And finally, I understand your reason for not wanting EF to enforce the relationship if you aren't going to always deal with teh full graph.最后,如果您不打算始终处理完整图表,我理解您不希望 EF 强制执行关系的原因。 I think 1:1 relationships are the most confusing of the EF relationship mappings and I always find myself having to go back for reminders of the rules and how things should work.我认为 1:1 关系是 EF 关系映射中最令人困惑的,我总是发现自己必须返回以获取规则提醒以及事情应该如何运作。

Old question.老问题。 But since EF6 is still used and even available for.Net standard and this issue can be a real nuisance, I think it's worth mentioning something I couldn't find in other answers.但由于 EF6 仍在使用,甚至可用于 .Net 标准,而且这个问题可能是一个真正的麻烦,我认为值得一提的是我在其他答案中找不到的东西。

It is true that both HasRequired - WithRequiredPrincipal and HasOptional - WithRequired produce the same database schema and the same runtime behavior.确实, HasRequired - WithRequiredPrincipalHasOptional - WithRequired产生相同的数据库模式和相同的运行时行为。 That is, with both mappings it's possible to save a principal without a dependent entity and to remove the dependent later.也就是说,对于这两种映射,都可以在没有依赖实体的情况下保存主体,并在以后删除依赖实体。 So much for HasRequired . HasRequired

But there is a way to make EF validate the required relationship when creating the entities , which is by simply adding a [Required] attribute:但是有一种方法可以让 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; }
}

As said, only when creating the entities.如前所述,仅在创建实体时。 It's still possible to set RequiredPrincipalA.RequiredDependentA = null and save it successfully.仍然可以设置RequiredPrincipalA.RequiredDependentA = null并成功保存。 But I think that, fortunately, the likelihood of that happening in code is far lower than forgetting to set the required dependent.但我认为,幸运的是,代码中发生这种情况的可能性远低于忘记设置所需的依赖项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM