这是一个.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 Docs,EFCore.com那里获得一些帮助,浏览了几篇SO帖子,但我未能缩小范围。.
过去五天左右我所做的步骤..
无法确定类型为“ ICollection”的导航属性“ Doctor.Appointments”所表示的关系
删除了Doctor / Patient类中的导航属性解决了该问题,但这显然不是目的。如果我理解,那就意味着我需要扫描约会表中的每条记录,并筛选“ Doctor”是否等于某些Doctor。
我尝试使用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设置上的细微之处,但可能是错的。.我相信问题在于级联如何链接。
UDPATE :
好的,最终我发现这是一个设计问题,对其进行重新设计有助于解决它。 医生和患者类引用了约会,而约会引用了医生 >和患者。
为什么会出现问题:如果删除了患者,则级联删除操作会触发删除具有所有对Doctor Location的引用的约会,等等。也是对位置的引用,某些位置条目将按照级联顺序被删除两次。
解决方案: 依靠发现,不要尝试创建来回引用(始终具有导航属性)。
患者的导航属性为:约会->的导航属性为医生->的导航属性为< strong>位置。这使导航更多的是直线而不是圆形。
在此先感谢您的帮助!
答案 0 :(得分:0)
我敢肯定,使用当前设置进行此操作的唯一方法是更改以下行:
.OnDelete(DeleteBehavior.Cascade);
到
.OnDelete(DeleteBehavior.SetNull);
答案 1 :(得分:0)
我已更新问题,以标记通过重新设计数据结构和导航属性已解决该问题。 如果有人遇到类似的问题,将其保留在那里可以提供帮助。
致敬