代码优先:EntityFramework-一对多关系上的迁移错误

时间:2019-07-10 11:36:19

标签: c# code-first asp.net-core-2.2 entity-framework-core-2.2

这是一个.NET Core应用2.2。使用EF Core。代码优先。我还是一个初中生,为了自己的学习尝试了一些更重的项目。

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

医生患者都有很多约会医生和许多患者患者和许多医生。 (或具有相同的Pat / Doc)。 在两个类中对“约会”的引用如下:

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

约会中,医生患者都是必需的。因为没有任何一项,预计不会进行约会。

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

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

当它们在某个会议上对齐时,将创建时间,位置等。然而,约会应同时具有医生患者的引用。

当某些用户被删除时,我也需要删除相关的约会。但不相关的其他用户,位置等。

添加迁移已创建。我要更新数据库时发生错误。

迁移文件的一部分。奇怪的是,一次在Restrict中一次在Cascade中添加DoctorID作为FK。 问题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);

该错误消息涉及循环引用的问题,但是我看不到它是诚实的-除非出现以下情况:删除医生->触发约会的删除->触发患者的删除(显然不是目的)

  

错误:引入了FOREIGN KEY约束'FK_Appointment_Patients_Id'   在表“约会”上可能会导致循环或多个级联路径。   指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他   外键约束。

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

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

过去五天左右我所做的步骤..

  1. 我尝试从约会类的医生患者中删除必需标签。 结果为:
  

无法确定类型为“ ICollection”的导航属性“ Doctor.Appointments”所表示的关系

  1. 删除了Doctor / Patient类中的导航属性解决了该问题,但这显然不是目的。如果我理解,那就意味着我需要扫描约会表中的每条记录,并筛选“ Doctor”是否等于某些Doctor。

  2. 我尝试使用DoctorId和PatientId将新的外键添加到约会类中,但似乎是由迁移自动完成的(在迁移文件中创建了FK密钥相应地)。无论如何,它导致了相同的错误。

    公共向导DoctorId {get;组; } 公共Guid PatientId {组; }

问题2 :可能有些愚蠢,但我的理解是约会与Doctor and Patient有一对多的关系,因此不确定Join Table类是否有帮助? 但是在这种情况下,级联删除是如何工作的?

即::我创建一个 ComboDocApp 类,该类引用了一个 Doctor 和一个约会医生有一个ICollection,约会也有一个ICollection。但这似乎很奇怪,因为约会只需要一个 ComboDocApp

编辑: 好的,在评论之后,我创建了一个名为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);

但错误仍然存​​在:

  

在表'ComboDocPatAppLoc'上引入FOREIGN KEY约束'FK_ComboDocPatAppLoc_Patients_Id'可能会导致循环或多个级联路径

我感觉缺少ModelBuilder设置上的细微之处,但可能是错的。.我相信问题在于级联如何链接。

  • 如果我删除医生 / 患者->,我需要 约会 ComboDocPatAppLoc 已删除。
  • 如果我删除约会->,我需要 ComboDocPatAppLoc 已删除。
  • 如果我删除位置->我需要进行约会
    删除。

UDPATE

好的,最终我发现这是一个设计问题,对其进行重新设计有助于解决它。 医生患者类引用了约会,而约会引用了医生 >和患者

为什么会出现问题:如果删除了患者,则级联删除操作会触发删除具有所有对Doctor Location的引用的约会,等等。也是对位置的引用,某些位置条目将按照级联顺序被删除两次。

解决方案: 依靠发现,不要尝试创建来回引用(始终具有导航属性)。

患者的导航属性为:约会->的导航属性为医生->的导航属性为< strong>位置。这使导航更多的是直线而不是圆形。

在此先感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

我敢肯定,使用当前设置进行此操作的唯一方法是更改​​以下行:

.OnDelete(DeleteBehavior.Cascade);

.OnDelete(DeleteBehavior.SetNull);

答案 1 :(得分:0)

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

致敬