OnDelete(DeleteBehavior.Cascade) 可能会导致循环或多个级联路径

Posted

技术标签:

【中文标题】OnDelete(DeleteBehavior.Cascade) 可能会导致循环或多个级联路径【英文标题】:OnDelete(DeleteBehavior.Cascade) may cause cycles or multiple cascade paths on 【发布时间】:2022-01-05 07:13:46 【问题描述】:

我有一个 Products 表和一个 Categories 表。我正在尝试在产品和类别之间建立多对多的关系。所以我有一个名为:ProductCategories 的表 - 我遵循了官方文档:

https://docs.microsoft.com/en-us/ef/core/modeling/relationships?tabs=fluent-api%2Cfluent-api-composite-key%2Csimple-key

public class ProductCategory

    public Guid ProductId  get; set; 
    public Product  Product  get; set; 
    
    public Guid CategoryId  get; set; 
    public Category  Category  get; set; 


 public class Product

     public Product()
    
        ProductFiles = new Collection<ProductFiles>();
    
    
    public Company Company  get; set; 
    public Guid CompanyId  get; set; 
    
    public string Name  get; set; 
    public string Description  get; set; 
    public decimal SalePrice  get; set; 
    public decimal? CostPrice  get; set; 
    public int VatPercentage  get; set;  = 25;

    public ICollection<ProductFiles> ProductFiles  get; set; 
    
    public ICollection<ProductCategory> Categories  get; set; 


public class Category

   public string Title  get; set; 
    
    public Guid CompanyId  get; set; 
    public Company Company  get; set; 
    public Guid? ParentCategoryId  get; set; 
    public virtual ICollection<Category> SubCategories  get; set; 
    public virtual Category ParentCategory  get; set; 
    
    public bool Visible  get; set;  = true;

    public int SortOrder  get; set;  = 1;
    
    public ICollection<ProductCategory> Products  get; set; 

在模型构建器中我已经指定了关系

        builder.Entity<Company>()
            .HasMany(c => c.Products)
            .WithOne(e => e.Company);
        

        builder.Entity<Product>()
            .Property(p => p.CostPrice)
            .HasColumnType("decimal(18,2)"); 
        
        builder.Entity<Product>()
            .Property(p => p.SalePrice)
            .HasColumnType("decimal(18,2)");

        builder.Entity<Category>()
            .HasMany<Category>(c => c.SubCategories)
            .WithOne(c => c.ParentCategory)
            .HasForeignKey(c => c.ParentCategoryId)
            .OnDelete(DeleteBehavior.Restrict);
        
        builder.Entity<Company>()
            .HasMany<Category>(p => p.Categories)
            .WithOne(p => p.Company)
            .HasForeignKey(p => p.CompanyId).OnDelete(DeleteBehavior.Cascade);

builder.Entity() .HasKey(x => new x.ProductId, x.CategoryId);

        builder.Entity<ProductCategory>()
            .HasOne<Product>(pc => pc.Product)
            .WithMany(p => p.Categories)
            .HasForeignKey(p => p.ProductId);

        builder.Entity<ProductCategory>()
            .HasOne<Category>(p => p.Category)
            .WithMany(p => p.Products)
            .HasForeignKey(p => p.CategoryId);

问题是当我尝试更新数据库时出现错误“可能导致循环或多个级联路径。指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他外键约束。 无法创建约束或索引。”

我想要的是当系统中的某人删除一个类别/产品时,它应该删除 ProductCategories 中的记录 - 当我尝试添加 onDelete 没有操作时,如果没有它们在 ProductsCategory 中的关系,我就无法删除该类别/产品表。

关于如何以最佳方式解决此问题的任何建议?

【问题讨论】:

我猜你的班级结构应该改变。首先,您的Product 不能只包含Categories。它应该有 ID、一些产品属性,然后是类别列表。然后类别将是类别列表,而不是产品列表。 ProductCategories 将是产品和类别的查找表(但它只包含 ID)。现在类结构不正确。 我在产品和类别中有多个属性。我刚刚删除了它们,因为它没有使帖子太大:) 另外,您删除了导致此错误的其他关联。你展示的模型不能扔。无论哪种方式,错误都是硬数据库约束。它只能通过使至少一个关联不级联来解决。 我已在 Category 和 Products 表中添加了所有内容 :) 见my question和explained article with solution 【参考方案1】:

Company 配置为对 Category 和 Product 级联删除。那是“多级联路径”,是不允许的。将所有 FK 配置放在一起,以便更轻松地查看哪些关系可以级联。例如

    builder.Entity<Company>()
        .HasMany(c => c.Products)
        .WithOne(e => e.Company)
        .OnDelete(DeleteBehavior.Cascade);

    builder.Entity<Company>()
       .HasMany(p => p.Categories)
       .WithOne(p => p.Company)
       .HasForeignKey(p => p.CompanyId)
       .OnDelete(DeleteBehavior.Restrict);

    builder.Entity<Category>()
        .HasMany(c => c.SubCategories)
        .WithOne(c => c.ParentCategory)
        .HasForeignKey(c => c.ParentCategoryId)
        .OnDelete(DeleteBehavior.Restrict);

    builder.Entity<ProductCategory>()
        .HasOne(pc => pc.Product)
        .WithMany(p => p.Categories)
        .HasForeignKey(p => p.ProductId)
        .OnDelete(DeleteBehavior.Cascade);

    builder.Entity<ProductCategory>()
        .HasOne(p => p.Category)
        .WithMany(p => p.Products)
        .HasForeignKey(p => p.CategoryId)
        .OnDelete(DeleteBehavior.Cascade);

【讨论】:

以上是关于OnDelete(DeleteBehavior.Cascade) 可能会导致循环或多个级联路径的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI List .onDelete:索引超出范围

Laravel 外键 onDelete('cascade') 不起作用

onDelete 附加到 ForEach 但没有滑动手势

Swiftui foreach 索引超出范围 ondelete 问题

SwiftUI .onDelete 抛出致命错误:索引超出范围

使用 onDelete 时索引超出范围