[英]How to avoid cycles when introducing FOREIGN KEY constraint in a table?
I'm using code-first approach with EF Core 6 to construct the database and its tables.我在EF Core 6中使用代码优先方法来构建数据库及其表。 The problem is that when I update the database, I get an error regarding cycles or multiple cascade paths.
问题是当我更新数据库时,我收到关于循环或多个级联路径的错误。 I searched the same questions but none of them could solve my problem.
我搜索了相同的问题,但没有一个可以解决我的问题。 My entity classes are:
我的实体类是:
public class User
{
[Key]
public int UserId { get; set; }
[Required]
[DataType(DataType.Text)]
public string Username { get; set; }
[Required]
[DataType(DataType.Text)]
public string Password { get; set; }
[Required]
[DataType(DataType.Text)]
public string UserRole { get; set; }
[Required]
public bool IsActive { get; set; }
[Required]
public bool CanAccessNotifications { get; set; }
[Required]
public bool CanAccessMessages { get; set; }
[Required]
public bool CanAccessFiles { get; set; }
[Required]
public bool CanAccessPmDatabase { get; set; }
[Required]
public bool CanMakeChangesToPmDatabase { get; set; }
[Required]
public bool IsLocked { get; set; }
[Required]
public bool CanLocked { get; set; }
//Navigation properties
public virtual CostCenter CostCenter { get; set; }
public virtual List<PmSchedule> PmSchedules { get; set; }
}
public class ServiceType
{
[Key]
public int ServiceTypeId { get; set; }
[Required]
[DataType(DataType.Text)]
public string Title { get; set; }
[Required]
public bool IsActive { get; set; } = true;
//Navigation properties
public virtual List<PmDataSet> PmDataSets { get; set; }
public virtual List<PmSchedule> PmSchedules { get; set; }
}
public class PmSchedule
{
[Key]
public long PmScheduleId { get; set; }
[Required]
public long PmNumber { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime ScheduledStartDate { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime ScheduledEndDate { get; set; }
[Required]
[DataType(DataType.Text)]
public string MainFileName { get; set; }
[DataType(DataType.Text)]
public string? UploadedFileName { get; set; }
[Required]
public int MainUploader { get; set; }
public int? Uploader { get; set; }
[DataType(DataType.DateTime)]
public DateTime? CompletionDate { get; set; }
[Required]
[DataType(DataType.Text)]
public string? Status { get; set; }
//Navigation properties
public virtual CostCenter CostCenter { get; set; }
public virtual ServiceType ServiceType { get; set; }
}
public class PmDataSet
{
[Key]
public long PmDataSetId { get; set; }
[Required]
public long PmNumber { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime ScheduledStartDate { get; set; }
[Required]
[DataType(DataType.DateTime)]
public DateTime ScheduledEndDate { get; set; }
[Required]
[DataType(DataType.Text)]
public string WorkOrderNumber { get; set; }
[Required]
[DataType(DataType.Text)]
public string Priority { get; set; }
[Required]
[DataType(DataType.Text)]
public string Activity { get; set; }
[DataType(DataType.DateTime)]
public DateTime? StartTime { get; set; }
[DataType(DataType.DateTime)]
public DateTime? EndTime { get; set; }
[Required]
public int ActualDuration { get; set; }
[Required]
public int StandardDuration { get; set; }
[Required]
[DataType(DataType.Text)]
public string Executor { get; set; }
[DataType(DataType.Text)]
public string? Expaination { get; set; }
//Navigation properties
public virtual ServiceType ServiceType { get; set; }
public virtual CostCenter CostCenter { get; set; }
public virtual Equipment Equipment { get; set; }
}
public class Equipment
{
[Key]
public long EquipmentId { get; set; }
[Required]
[DataType(DataType.Text)]
public string EquipmentCode { get; set; }
[Required]
[DataType(DataType.Text)]
public string EquipmentTitle { get; set; }
//Navigation properties
public virtual CostCenter CostCenter { get; set; }
public virtual List<PmDataSet> PmDataSets { get; set; }
}
public class CostCenter
{
[Key]
public int CostCenterId { get; set; }
[Required]
[DataType(DataType.Text)]
public string Title { get; set; }
[Required]
public bool IsActive { get; set; } = true;
//Navigation properties
public virtual List<PmDataSet>? PmDataSets { get; set; }
public virtual List<PmSchedule>? PmSchedules { get; set; }
public virtual List<Equipment>? Equipments { get; set; }
public virtual List<User>? Users { get; set; }
}
My context class:我的上下文 class:
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
I get the following error when update the database:更新数据库时出现以下错误:
Introducing FOREIGN KEY constraint 'FK_PmDataSets_Equipments_EquipmentId' on table 'PmDataSets' may cause cycles or multiple cascade paths.
在表“PmDataSets”上引入 FOREIGN KEY 约束“FK_PmDataSets_Equipments_EquipmentId”可能会导致循环或多个级联路径。 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 约束。 Could not create constraint or index.
无法创建约束或索引。 See previous errors.
请参阅以前的错误。
you need to add some extra config like this:您需要添加一些额外的配置,如下所示:
protected override void OnModelCreating(ModelBuilder mb)
{
var pmConfig = mb.Entity<PmDataSet>();
pmConfig.HasOne(n => n.Equipment).WithMany(n => n.PmDataSets).OnDelete(DeleteBehavior.NoAction);
}
the problem is your Equipment model or/and some others already has at least one cascade delete relation, so if you add another cascade delete relation there will be a chain deletion if one of these entities got deleted.问题是您的设备 model 或/和其他一些已经具有至少一个级联删除关系,因此如果您添加另一个级联删除关系,如果其中一个实体被删除,则会出现链式删除。 so you need to tell ef that some/none of these relations are not cascading while deleting.
所以你需要告诉 ef 这些关系中的一些/没有一个在删除时没有级联。
(A) <-- cascade --> (B) (A) <-- 级联 --> (B)
(B) <-- cascade --> (C) so there will be a logical cascade between A and C, that is not arbitrary. (B) <-- 级联 --> (C) 所以在 A 和 C 之间会有一个逻辑级联,这不是任意的。
with a little playing with that config you will solve your problem;)稍微玩一下该配置,您将解决您的问题;)
-------- update to answer the commented question u can go by ef convictions: -------- 更新以回答评论的问题,您可以通过 ef 信念 go:
public User MainUploader { get; set; }
[Required]
public int MainUploaderId { get; set; }
public User Uploader { get; set; }
public int? UploaderId { get; set; }
you also can use [ForeignKey("fkName")] annotation if you want to use another way of naming your properties, or use fluent API ForeignKey(a=> a.something) method or its overlods.如果您想使用另一种命名属性的方式,也可以使用 [ForeignKey("fkName")] 注释,或者使用流畅的 API ForeignKey(a=> a.something) 方法或其重载。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.