繁体   English   中英

Entity Framework Core 中的一对一关系

[英]One-to-One relationship in Entity Framework Core

在过去的几周里,我一直在研究 .NET Core,并决定尝试使用 EF Core(来自 ASP.NET MVC with NHibernate)。 经过一番挖掘后,我发现了一个名为EF Visual Designer的不错的扩展。 它允许我直观地创建 model 并生成代码。

我已经定义了图中所示的简单一对一关系: Simple one-to-one relationship

生成代码后,我得到以下 Fluent API 代码:

modelBuilder.Entity<Authentication>()
   .ToTable("Authentications")
   .HasKey(t => t.Id);

modelBuilder.Entity<Authentication>()
    .Property(t => t.Id)
    .IsRequired()
    .ValueGeneratedOnAdd();

modelBuilder.Entity<User>()
     .ToTable("Users")
     .HasKey(t => t.Id);

modelBuilder.Entity<User>()
     .Property(t => t.Id)
     .IsRequired()
     .ValueGeneratedOnAdd();

modelBuilder.Entity<User>()
    .HasOne(x => x.Authentication)
    .WithOne()
    .HasForeignKey("Authentication_Id")
    .IsRequired();

用户 class 具有以下(相关)属性:

public Class User {
    [Key]
    [Required]
    public Guid Id { get; set; }
    ...
    public virtual Authentication Authentication { get; set; }
}

身份验证具有以下(相关)属性:

public class Authentication  {
    [Key]
    [Required]
    public Guid Id { get; set; }
}

但是,当我尝试生成迁移时,出现以下错误:

您正在配置“User”和“Authentication”之间的关系,但在“Authentication_Id”上指定了一个外键。 必须在作为关系一部分的类型上定义外键。

我尝试切换到多对一关系并且没有任何问题。 这可能是一种解决方法,但不是一个非常干净的方法。 这可能是由于命名问题导致的,例如两个实体都将“Id”作为主键?

如果是这样,什么是“最佳实践”? 我是否为每个实体提供了唯一的 ID 列名称? 我如何 go 关于派生类都继承 ID 列的抽象实体?

您需要将外键放在另一个类上。 看来您在Authentication类上没有属性“ Authentication_Id”。

我从未使用过EF Visual Designer来生成代码,而只是通过查看您的代码,要么User实体需要Authentication的外键,要么Authentication实体需要User的外键。

假设您要将外键放在User

public class User
{
    [Key]
    [Required]
    public Guid Id { get; set; }

    public Guid AuthenticationId { get; set; }

    // Even this navigation property is optional
    // for configuring one-to-one relationship
    public virtual Authentication Authentication { get; set; }
}

public Authentication
{
    [Key]
    [Required]
    public Guid Id { get; set; }
}

然后,一对一关系应配置为:

modelBuilder.Entity<User>()
    .HasOne(x => x.Authentication)

    // Or like this if you don't have Authentication navigation property:
    //.HasOne<Authentication>()

    .WithOne()
    .HasForeignKey(x => x.AuthenticationId);

不,您不必为每个实体赋予唯一的ID列名称。 实际上,您可以在代码中调用任何内容,然后在配置中将其重命名:

modelBuilder.Entity<User>()
    .Property(x => x.Id).HasColumnName("WHATEVER_YOU_WANT_TO_CALL_IN_DB");

到目前为止所有做出回应的人都是对的。 您在依赖实体中缺少一个外键,因此您需要添加一个。 根据您的代码,它必须是“Authentication_Id”,因为这是您引用的名称——但您实际上没有声明一个!

其次, Vladislav Vazhenin是对的:

尝试在.HasForeignKey(x => x.AuthenticationId) 上构建时出错; 但是.HasForeignKey <User> (x => x.AuthenticationId); 为我工作

只需确保您指向导航属性而不是关联的实体密钥属性(Authentication 与 AuthenticationId)。 所以,考虑一下。

事实上,有人需要推动文档(似乎是用户编辑的)来包含这些细微的差异。 例如; .HasOne也有一个变种

.HasOne(x=>x.Authentication) 

.HasOne<Authentication>() 

包括一条注释,说明它们是否因 Entity Framework Core 的版本而异。 编译器有时会阻止或忽略其中一些可有可无或已弃用的命令变体。 但是我们需要知道哪个适用于哪个版本,以及流利的 api 覆盖数据注释是如何工作的(强调哪个优先)。

暂无
暂无

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

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