table 中多个 1:1 关系的 EF Core 3.1.7 数据注释

EF Core 3.1.7 Data annotations for multiple 1:1 relationships in table

我在确定数据注释以映射多个 1:1 关系以便 EF Core 3.11.7 理解它并可以构建迁移时遇到问题。

我有一个人 table 和一个笔记 table。 Person 中存在 0:M Notes 关系。一个人的记录可以有 0 个或多个注释。

在注释中 table 是一个 CreatedBy 字段,它是一个人。它还有一个 LastEditedBy 字段,它也是一个人。 EF 一直在轰炸如何为 Note.CreatedBy 构建关系。如果这不是 EF,则两个字段都将是具有适当人员记录的 PersonID 的整数。如何向 EF Core 解释这一点,最好使用数据注释?

当我尝试创建迁移时失败并显示: System.InvalidOperationException: 无法确定类型 'Person' 的导航 属性 'Note.CreatedBy' 表示的关系。手动配置关系,或使用“[NotMapped]”属性或使用 'OnModelCreating'.

中的 'EntityTypeBuilder.Ignore' 忽略此 属性
    using System;
    using System.Collections.Generic;
    using System.ComponentModel.DataAnnotations;
    using System.ComponentModel.DataAnnotations.Schema;
    using System.Linq;
    using System.Threading.Tasks;

namespace VetReg.Domain.Model
{
    public class Family
    {
        public int FamilyID { get; set; } = -1;
        public string FamilyName { get; set; }
        public List<Pet> Pets { get; set; } = new List<Pet>();
        public List<PersonFamily> People { get; set; }
        public int AddressID { get; set; } = -1;
        public List<Note> Notes { get; set; }
    }

    public class Person
    {
        public int PersonID { get; set; }
        public string LastName { get; set; }
        public string FirstName { get; set; }
        public DateTime? Birthdate { get; set; }
        public string Password { get; set; }
        public List<PersonFamily> Families { get; set; }
        public List<Note> Notes { get; set; }
    } // class People

    public class Note
    {
        public int NoteID { get; set; }

        public int CreatedByID { get; set; }

        [ForeignKey("CreatedByID")]
        public Person CreatedBy { get; set; }
        public DateTime DateCreated { get; set; }

        public int LastEditByID { get; set; }

        [ForeignKey("LastEditByID")]
        public Person LastEditBy { get; set; }
        public DateTime? LastEditDate { get; set; }
        public string NoteText { get; set; }
    }

    public class PersonFamily
    {
        public int PersonID { get; set; }
        public int FamilyID { get; set; }
        public Person Person { get; set; }
        public Family Family { get; set; }
    }

}

问题是(这就是 EF 无法自动确定关系的原因)Person.NotesNote.CreatedBy / Note.LastEditBy - [=49= 之间的关系是什么] 大概?您已经说过 PersonNote 之间存在 0:M 关系,但请注意那里可能存在 3 one-to-many 关系 - 与人相关的笔记、由人创建的笔记和由个人编辑的笔记,这可能会导致 3 个 FK 给笔记中的人。

另请注意,none 的导航属性是必需的,但如果存在,它们必须成对出现。

假设你想要 3 个关系,即 Note.CreatedBy / Note.LastEditByPerson.Notes 之间没有关系,你需要告诉 EF Note.CreatedByNote.LastEditByPerson中没有相应的(a.k.a.inverse)导航属性。这对于数据注释是不可能的。为此目的唯一可用的数据注释 [InverseProperty(...)] 不接受 empty/null 字符串名称,因此不能用于此处需要的内容。

这里还有一个问题,解决当前后会遇到,同样是数据注解无法解决的问题。由于您有从 PersonNote 的多个必需(因此默认情况下是级联删除)关系,它会在 SqlServer 中产生著名的“循环或多个级联路径”问题,并且需要关闭至少一个级联删除。

话虽如此,有问题的模型需要以下最小流畅配置:

modelBuilder.Entity<Note>()
    .HasOne(e => e.CreatedBy)
    .WithMany()
    .OnDelete(DeleteBehavior.Restrict);

modelBuilder.Entity<Note>()
    .HasOne(e => e.LastEditBy)
    .WithMany()
    .OnDelete(DeleteBehavior.Restrict);

原始问题的关键是 HasOne / WithMany 对。执行此操作后,EF Core 会自动将未映射的 Person.Notes 集合映射到第三个可选关系,没有反向导航 属性 和影子 FP 属性(和列)称为“PersonId”,即相当于

modelBuilder.Entity<Person>()
    .HasMany(e => e.Notes)
    .WithOne()
    .HasForeignKey("PersonId");

关于多个级联路径的第二个问题,您可以使用任何非级联选项或更新的 ClientCascade 而不是 Restrict。它可能只是其中一种关系,一旦它打破了“级联路径”(显然你不能打破循环,因为它是模型所要求的)。