【问题标题】:How to create one-to-one relationship in Entity Framework Core?如何在 Entity Framework Core 中创建一对一的关系?
【发布时间】:2019-12-30 13:11:08
【问题描述】:

让我们从一对多关系开始:

public sealed class MyContext : DbContext
{
  protected override void OnModelCreating(ModelBuilder builder)
  {
    builder.Entity<Slave>()
           .HasOne(typeof(Master))
           .WithMany() // *
           .HasForeignKey(nameof(Slave.ForeignField));
  }
}

所以我声明主表中的每一条记录我可以在从表中拥有多条记录。当我运行 EF 工具来构建迁移时,这被接受并且工作正常。

但是当我将标有星号的行更改为:

           .WithOne()

为了建立一对一的关系,迁移失败并出现错误:

您正在配置 'Slave' 和 'Master' 之间的关系,但是 在“ForeignField”上指定了一个外键。外键必须 在属于关系一部分的类型上定义。

我不明白,就在一秒钟前,给定的字段(C# 术语中的属性)还可以,现在 EF 声称找不到它?

我错过了什么?如何让EF开心?

记录类型如下——请注意有没有导航属性。

internal sealed class Slave
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public Guid InstanceId { get; set; }

    public Guid ForeignField { get; set; }
}

internal sealed class Master
{
    [Key]
    [DatabaseGenerated(DatabaseGeneratedOption.None)]
    public Guid Id { get; set; }
}

目前我使用原始 SQL 解决了这个问题,它可以工作,但我仍然很好奇这里出了什么问题。


感谢@AminGolmahalle 的回答,我的好奇心被触发了为什么以及我可以以通用形式使用HasForeignKey。这让我发现我不能,但更重要的是 WithOneWithMany 不是 1:1 的替代品。两者都会导致不同的重载。

所以第一个版本的一对多工作,因为我遇到了正确的重载,第二个没有,因为我传递了不正确的参数。正确的版本是:

builder.Entity<Slave>()
       .HasOne(typeof(Master))
       .WithOne() 
       .HasForeignKey(nameof(Slave), nameof(Slave.ForeignField)); // changed

第一个参数必须是从表的名称(再次)。

但是最好切换到通用版本(请参阅已接受答案下的最后一条评论)并首先避免出现这种“愚蠢”错误的可能性。

【问题讨论】:

    标签: c# entity-framework-core one-to-one


    【解决方案1】:

    下面的代码只是一对一关系的示例:

    public class Author
    {
        public int AuthorId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public AuthorBiography Biography { get; set; }
    }
    public class AuthorBiography
    {
        public int AuthorBiographyId { get; set; }
        public string Biography { get; set; }
        public DateTime DateOfBirth { get; set; }
        public string PlaceOfBirth { get; set; }
        public string Nationality { get; set; }
        public int AuthorRef { get; set; }
        public Author Author { get; set; }
    }
    

    您可以在 EntityFramework 中将 FluentApi 用于关系:

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Author>()
            .HasOne(a => a.Biography)
            .WithOne(b => b.Author)
            .HasForeignKey<AuthorBiography>(b => b.AuthorRef);
    }
    

    使用 FluentApiDataAnotaion 好得多。

    FluentApi In Asp Core

    I Suggest To You Read About FluentValidation

    【讨论】:

    • 非常感谢,我无法使用您的解决方案(因为我没有导航属性),但是您的代码引发了我的好奇心,为什么您使用通用 HasForeignKey。事实证明WithOneWithMany 导致不同的重载。
    • 欢迎您。您需要在模型中编写导航属性。因为当您想要使用实体框架从数据库中调用数据时。如果没有导航属性,您将无法做到这一点。
    • 我知道,但我没有这种需要。我想要的只是数据完整性,仅此而已。
    • 太好了,它比我的修复要好,因为它避免了出错的机会。再次谢谢你! :-)
    【解决方案2】:
    猜你喜欢
    • 2017-02-17
    • 1970-01-01
    • 2019-08-07
    • 1970-01-01
    • 2020-08-10
    • 1970-01-01
    • 2019-07-30
    • 2020-03-12
    • 1970-01-01
    相关资源
    最近更新 更多