代码优先:EntityFramework - One-To-Many 关系上的迁移错误

Code First: EntityFramework - Migration Error on One-To-Many relation

这是一个 .NET Core 应用程序 2.2。使用 EF 核心。代码优先。我有点初级,正在为自己的学习尝试更重的项目。

要简化模型结构,请参阅:model-structure。 基本上有一个抽象的默认用户 - 由 Doctor 和 Patient 继承。

医生患者都有很多约会医生有许多患者患者有许多医生。 (或使用相同的 Pat/Doc)。 class 中对 Appointments 的引用如下所示:

public virtual ICollection<Appointment> Appointments { get; set; }

预约中,医生患者都是必需的。因为没有他们中的任何一个,预计不会发生约会。

[Required]
    public Doctor Doctor { get; set; }

[Required]
    public Patient Patient { get; set; }

当他们在某些会议上对齐时,时间、地点等就会创建。然而 Appointment 应包含 DoctorPatient 的参考。

当某个用户被删除时,我需要删除相关的约会。但不是相关的other-user、位置等

Add-Migration 已创建。当我想 Update-Database.

时出现错误

迁移文件的一部分。奇怪的是,DoctorID 被添加为 FK,一次是使用 Restrict,一次是使用 Cascade。 问题 1)不确定这是否正确,我是否可以直接触摸它?

migrationBuilder.CreateTable(
name: "Appointment",
columns: table => new
{
    Id = table.Column<Guid>(nullable: false),
    LocationId = table.Column<Guid>(nullable: false),
    CreatedDate = table.Column<DateTime>(nullable: false),
    StartTime = table.Column<DateTime>(nullable: false),
    Duration = table.Column<TimeSpan>(nullable: false),
    FollowUpAppointmentId = table.Column<Guid>(nullable: true),
    DoctorId = table.Column<Guid>(nullable: true)
},
constraints: table =>
{
    table.PrimaryKey("PK_Appointment", x => x.Id);
    table.ForeignKey(
        name: "FK_Appointment_Doctors_DoctorId",
        column: x => x.DoctorId,
        principalTable: "Doctors",
        principalColumn: "Id",
        onDelete: ReferentialAction.Restrict);
    table.ForeignKey(
        name: "FK_Appointment_Doctors_Id",
        column: x => x.Id,
        principalTable: "Doctors",
        principalColumn: "Id",
        onDelete: ReferentialAction.Cascade);
    table.ForeignKey(
        name: "FK_Appointment_Patients_Id",
        column: x => x.Id,
        principalTable: "Patients",
        principalColumn: "Id",
        onDelete: ReferentialAction.Cascade);
}};

在 ApplicationDbContext 中,我使用 Fluent API 来配置关系。

builder.Entity<Doctor>()
    .HasMany<Appointment>(ap => ap.Appointments)
    .WithOne(d => d.Doctor)
    .HasForeignKey(fk => fk.Id)
    .OnDelete(DeleteBehavior.Cascade);

builder.Entity<Patient>()
    .HasMany<Appointment>(ap => ap.Appointments)
    .WithOne(p => p.Patient)
    .HasForeignKey(fk => fk.Id)
    .OnDelete(DeleteBehavior.Cascade);

错误消息指的是循环引用的问题,但我看不出它是诚实的 - 除非在以下情况下:医生被删除 --> 触发约会删除 --> 触发患者删除(这显然不是本意)

Error: Introducing FOREIGN KEY constraint 'FK_Appointment_Patients_Id' on table 'Appointment' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

我不确定这是设计问题还是编码问题。

我试图从 MS Docs, from EFCore.com 那里获得一些帮助,浏览了几个 SO 帖子但我未能缩小范围..

我在过去五天左右完成的步骤..:[=​​23=]

  1. 我试图从 DoctorPatient 中删除 Appointment 中的 Required 标签 class。 结果是:

Unable to determine the relationship represented by navigation property 'Doctor.Appointments' of type 'ICollection'

  1. 删除了 Doctor/Patient 中的导航 属性 classes 解决了问题,但这显然不是本意。如果我理解这意味着我需要扫描 Appointment table 中的每条记录并过滤 Doctor equals for certain Doctor。

  2. 我尝试用 DoctorId 和 PatientId 添加一个新的外键到 Appointment class,但它似乎是由迁移(在迁移文件中相应地创建 FK 密钥)。无论如何,它导致了同样的错误。

    public Guid DoctorId { get;放; } public Guid PatientId { 得到;放; }

问题 2:可能有点蠢,但我的理解是 Appointment 与 Doctor 和 Patient 有 one-to-many 关系,所以不确定 Join Table class会有帮助吗? 但在那种情况下,级联删除是如何工作的?

即:我创建了一个 ComboDocApp class,它参考了一个 Doctor 和一个 约会Doctor 有一个 ICollection,Appointment 也有一个 ICollection。然而,这似乎很奇怪,因为约会只需要一个ComboDocApp

编辑: 好的,所以在评论之后我创建了一个新的 class 名为 ComboDocPatAppLoc.

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

    [Required]
    public Doctor Doctor { get; set; }
    public Guid DoctorId { get; set; }

    [Required]
    public Patient Patient { get; set; }
    public Guid PatientId { get; set; }

    [Required]
    public Appointment Appointment { get; set; }
    public Guid AppointmentId { get; set; }

    [Required]
    public Location Location { get; set; }
    public Guid LocationId { get; set; }
}

在 ApplicationDbContext 中,我创建了如下关系:

builder.Entity<ComboDocPatAppLoc>()
    .HasKey(key => new { key.DoctorId, key.PatientId, key.AppointmentId, key.LocationId });

builder.Entity<ComboDocPatAppLoc>()
    .HasOne(d => d.Doctor)
    .WithMany(cdpa => cdpa.ComboDocPatAppLoc)
    .HasForeignKey(fk => fk.Id);

builder.Entity<ComboDocPatAppLoc>()
    .HasOne(p => p.Patient)
    .WithMany(cdpa => cdpa.ComboDocPatAppLoc)
    .HasForeignKey(fk => fk.Id);

builder.Entity<ComboDocPatAppLoc>()
    .HasOne(l => l.Location);

builder.Entity<ComboDocPatAppLoc>()
    .HasOne(app => app.Appointment)
    .WithOne(cdpa => cdpa.ComboDocPatAppLoc);

但错误仍然存​​在:

Introducing FOREIGN KEY constraint 'FK_ComboDocPatAppLoc_Patients_Id' on table 'ComboDocPatAppLoc' may cause cycles or multiple cascade paths

我觉得缺少 ModelBuilder 设置中的微小部分,但可能是错误的。我认为问题在于级联的链接方式。

UDPATE:

好吧,最终我发现这是一个设计问题,重新设计有助于解决它。 DoctorPatient classes 引用了 Appointments Appointments 引用了 DoctorsPatients

为什么这是一个问题:如果 患者 被删除,级联删除将触发删除所有引用的预约Doctor Location 等。由于 Doctor 还引用了 Location,因此某些 Location 条目将被级联序列删除两次。

解决方法: 依靠发现,不要尝试创建 back-and-forth 引用(导航属性全部长)。

Patient 的导航 属性 到:Appointments --> 导航 属性 到 Doctor --> 导航 属性 到 Location。这使得导航更像是直线而不是圆。

在此先感谢您的帮助!

我确定在您当前的设置中使用它的唯一方法是更改​​以下行:

.OnDelete(DeleteBehavior.Cascade);

.OnDelete(DeleteBehavior.SetNull);

我已更新问题以标记该问题已通过重新设计数据结构和导航属性得到解决。 如果有人遇到类似的问题,请将其保留在那里以提供帮助。

敬礼