简体   繁体   English

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

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

It's a .NET Core app 2.2. 这是一个.NET Core应用2.2。 With EF Core. 使用EF Core。 Code First. 代码优先。 I am kinda junior experimenting with a bit more heavier project for my own learning. 我还是一个初中生,为了自己的学习尝试了一些更重的项目。

To simplify the model structure see: model-structure . 为了简化模型结构,请参见: model-structure Basically there is an abstract default user - which is inherited by Doctor and Patient. 基本上有一个抽象的默认用户-它由Doctor and Patient继承。

Both Doctor and Patient have many Appointments . 医生病人都有很多约会 Doctor with many Patients , Patient with many Doctors . 很多病人病人有很多医生 看病 (or with the same Pat/Doc). (或具有相同的Pat / Doc)。 The reference to Appointments in both class looks like: 在两个类中对“约会”的引用如下:

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

In the Appointment both Doctor and Patient are Required. 预约中医生病人都是必需的。 As no Appointment is expected to happen without any of them. 由于没有任何人,预计不会发生约会。

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

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

When they align on certain meeting the timing, location etc are created. 当它们在某个会议上对齐时,将创建时间,位置等。 Yet the Appointment shall hold a reference for Doctor and Patient as well. 然而,该任命也应为医生患者提供参考。

When certain user is deleted I need the related Appointments to be deleted as well. 当某些用户被删除时,我也需要删除相关的约会。 But not the related other-user, location, etc. 但不相关的其他用户,位置等。

Add-Migration is created. 添加迁移已创建。 Error occurs when I want to Update-Database. 我要更新数据库时发生错误。

The part of the migration file. 迁移文件的一部分。 What is weird that DoctorID is added as FK once with Restrict and once with Cascade. 奇怪的是,一次在Restrict中一次在Cascade中添加DoctorID作为FK。 Question 1) Not sure if this is correct and if I can touch it directly? 问题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);
}};

In the ApplicationDbContext I used Fluent API to configure relations. 在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);

The error message refers to an issue to cycling references but I can't see it to be honest - unless in case of ie.: Doctor is deleted --> triggers deletion of Appointment --> triggering deletion of Patient (which is clearly not the intent) 该错误消息是关于循环引用的一个问题,但我看不出它是诚实的-除非出现以下情况:删除医生->触发约会的删除->触发患者的删除(这显然不是目的)

Error: Introducing FOREIGN KEY constraint 'FK_Appointment_Patients_Id' on table 'Appointment' may cause cycles or multiple cascade paths. 错误:在表'Appointment'上引入FOREIGN KEY约束'FK_Appointment_Patients_Id'可能会导致循环或多个级联路径。 Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. 指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。

I am unsure if this is a design issue or a coding issue. 我不确定这是设计问题还是编码问题。

I tried to get some help from MS Docs , from EFCore.com , browsed several SO posts yet I fail to get it narrowed down.. 我尝试从EFCore.com的 MS Docs获得一些帮助,浏览了几篇SO帖子,但未能缩小范围。

Steps I have made in the past five days or so..: 我过去五天左右的步骤:

  1. I have tried to remove the Required tag from Doctor and Patient in Appointment class. 我试图从 约会”类的“ 医生”和“ 患者”中删除“必需”标签。 It results in : 结果是:

Unable to determine the relationship represented by navigation property 'Doctor.Appointments' of type 'ICollection' 无法确定由类型为“ ICollection”的导航属性“ Doctor.Appointments”表示的关系

  1. Removed the navigation property in Doctor/Patient classes solved the issue yet this is clearly not the intent. 删除Doctor / Patient类中的navigation属性可以解决此问题,但这显然不是目的。 If I understand it would mean that I need to scan each record in Appointment table and filter for Doctor equals for certain Doctor. 如果我理解,那就意味着我需要扫描约会表中的每条记录,并筛选“ Doctor”是否等于某些Doctor。

  2. I tried to add a new foreign key to Appointment class with DoctorId and PatientId, but it seems that it is done automatically by the migration (in the migration file the FK key is created accordingly). 我尝试使用DoctorId和PatientId将新的外键添加到约会类中,但是似乎它是由迁移自动完成的(在迁移文件中会相应地创建FK密钥)。 Anyway it resulted in the same error. 无论如何,它导致了相同的错误。

    public Guid DoctorId { get; 公共Guid DoctorId { set; 组; } public Guid PatientId { get; }公共Guid PatientId {get; set; 组; } }

Question 2 : Might be dumb but my understanding is that Appointment has a one-to-many relationship with Doctor and Patient, so not sure if a Join Table class would help? 问题2 :可能有些愚蠢,但是我的理解是约会与Doctor and Patient有一对多的关系,所以不确定Join Table类是否会有所帮助? But in that case how cascading deletion works? 但是在那种情况下,级联删除是如何工作的呢?

ie.: I create a ComboDocApp class, which has reference for one Doctor and one Appointment . ::我创建一个ComboDocApp类,该类具有一个Doctor和一个Appointment的引用。 And Doctor has an ICollection and Appointment has also an ICollection. Doctor有一个ICollection,而约会也有一个ICollection。 Yet this seems to be strange as for Appointment only one ComboDocApp is needed. 但这似乎很奇怪,因为约会只需要一个ComboDocApp

EDIT: Ok, so after the comments I have created a new class called ComboDocPatAppLoc. 编辑:好的,所以在注释之后,我创建了一个名为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; }
}

In the ApplicationDbContext I have created the relations as the following: 在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);

Yet the error remains: 但是错误仍然存​​在:

Introducing FOREIGN KEY constraint 'FK_ComboDocPatAppLoc_Patients_Id' on table 'ComboDocPatAppLoc' may cause cycles or multiple cascade paths 在表'ComboDocPatAppLoc'上引入FOREIGN KEY约束'FK_ComboDocPatAppLoc_Patients_Id'可能会导致循环或多个级联路径

I feel like missing the tiny bits on the ModelBuilder settings, but might be wrong.. I believe the issue is how cascading is chained. 我感觉好像错过了ModelBuilder设置上的一些小细节,但可能是错误的。.我认为问题在于级联如何链接在一起。

  • If I remove a Doctor / Patient --> I need to have the Appointment and ComboDocPatAppLoc removed. 如果我删除了医生 / 患者 ->我需要删除约会ComboDocPatAppLoc
  • If I remove an Appointment --> I need to have a ComboDocPatAppLoc removed. 如果我删除约会 ->我需要删除ComboDocPatAppLoc
  • If I remove a Location --> I need to have an Appointment 如果我删除位置 ->我需要预约
    removed. 删除。

UDPATE : UDPATE

Ok, eventually I found it to be a design issue rather and reworking it helped to solve it. 好的,最终我发现这是一个设计问题,对其进行重新设计有助于解决它。 Doctor and Patient classes had a reference to Appointments and Appointments had a reference to Doctors and Patients . 医生患者班级都提到了约会任命里提到了医生患者

Why it was an issue : In case a Patient is deleted the cascading deletion would trigger deletion of the Appointment with all references to Doctor Location, etc. As Doctor had also a reference to Location the certain Location entry would have been deleted twice by cascading sequence. 问题原因 :如果删除患者,则级联删除会触发约会的删除,其中包括对Doctor Location的所有引用,等等。由于Doctor也引用了Location,因此该特定Location条目将按层叠顺序被删除两次。

Solution : Rely on Discovery and don't try to create back-and-forth references (navigation properties all along). 解决方案 :依靠发现,不要尝试创建前后引用(一直以来都是导航属性)。

Patient has a navigation property to: Appointments --> which has navigation property to Doctor --> which has navigation property to Location . 患者的导航属性为: 约会 ->对Doctor的导航属性->对Location的导航属性。 This made the navigation more of a straight line than circle. 这使得导航更多的是直线而不是圆形。

Thanks in advance for your help! 在此先感谢您的帮助!

I'm sure the only way to get this working with your current setup is to change the following line: 我敢肯定,使用当前设置进行此操作的唯一方法是更改​​以下行:

.OnDelete(DeleteBehavior.Cascade);

to

.OnDelete(DeleteBehavior.SetNull);

I have updated the question to flag that issue got resolved via redesigning the Data structure and the navigation properties. 我已经更新了问题,以标记通过重新设计数据结构和导航属性已解决该问题。 Keeping it there thus to help if anyone encounters similar concerns. 如果有人遇到类似的问题,将其保留在那里可以提供帮助。

Salute 敬礼

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

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