一对一关系级联删除

Cascade delete in one to one relationship

我想在 1:1 关系中进行级联删除,其中我将多个实体引用到一个实体。问题是在数据库更新时抛出一个错误

Introducing FOREIGN KEY constraint 'FK_dbo.CategoryArticles_dbo.Articles_Article_Id' on table 'CategoryArticles' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.

RoutingSeo 实体用于将 seo friendly url 存储在数据库中供以后使用。我的问题显然是 ArticleCategory 之间的 M:N 关系。有什么办法可以解决这个问题吗?

这是我的模型实体

public class Article : IEntity<int>
{
    public int Id { get; set; }

    public string Name { get; set; }

    public ICollection<Category> Categories { get; set; }

    [Required]
    public virtual RoutingSeo RoutingSeo { get; set; }
    public int RoutingSeoId { get; set; }

}

public class Category : IEntity<int>
{
    public int Id { get; set; }

    public string Name { get; set; }

    public ICollection<Article> Articles { get; set; }

    [Required]
    public virtual RoutingSeo RoutingSeo { get; set; }
    public int RoutingSeoId { get; set; }
}

public class SpecificProduct : IEntity<int>
{
    public int Id { get; set; }

    public string Name { get; set; }

    [Required]
    public RoutingSeo RoutingSeo { get; set; }        
    public int RoutingSeoId { get; set; }
}

public class RoutingSeo : IEntity<int>
{
    public int Id { get; set; }

    public string SeoRoute { get; set; }

    public Article Article { get; set; }
    public SpecificProduct SpecificProduct { get; set; }
    public Category Category { get; set; }
}

这是我的流利 api 代码,其中我指定级联删除

modelBuilder.Entity<Article>()
    .HasRequired(x => x.RoutingSeo)
    .WithOptional(x=>x.Article)
    .WillCascadeOnDelete();

modelBuilder.Entity<Category>()
    .HasRequired(x => x.RoutingSeo)
    .WithOptional(x=>x.Category)
    .WillCascadeOnDelete();

modelBuilder.Entity<SpecificProduct>()
    .HasRequired(x => x.RoutingSeo)
    .WithOptional(x=>x.SpecificProduct)
    .WillCascadeOnDelete();

你是对的,ArticleCategory之间是你的多对多关系:一个Article有零个或多个Categories并且每个Category 可以被零个或多个 Articles.

使用

如果你删除一个Article,它的Categories不能被自动删除,因为Category可能被其他Articles使用,即使它现在没用,entity framework不知道明天要不要用。毕竟,您指定每个 Category 可能被 0 或更多 Articles.

使用

同样,如果你删除一个Category,entity framework不能自动删除属于这个类别的Articles

这不同于一对多关系。例如,如果您有一个 Book 和它的 Pages 的一对多关系,那么每个 Book 都有零个或多个 Pages 并且每个 Page 正好属于一个 Book.

如果你删除 Book,那么 entity framework 知道它应该自动删除 Book 的所有 Pages,它们都是 Pages外键 BookId。如果 Entity Framework 只删除 Book,那么我们将有一堆 Pages,外键值指向不存在的 Book。所以在一对多关系中,entity framework 可以级联删除。

唉,在多对多中这是不可能的。

好的一面是,您可以删除 Category 的最后一个 Article,并保持 Category 不变。明天您可以添加一个使用此 Category.

的新 Article

因此,如果您想删除一篇文章,您必须手动将其从它使用的“类别”中删除:

遵循标准命名约定的多对多:

class Article
{
    public int Id {get; set;}
    // an Article belongs to zero or more Categories:
    public virtual ICollection<Category> Categories {get; set;}
    ...
}
class Category
{
    public int Id {get; set;}
    // a Category is used by zero or more Articles:
    public virtual ICollection<Article> Articles{get; set;}
    ...
}

别忘了声明您的 ICollections 是虚拟的!

class MyDbContext : DbContext
{
    public class DbSet<Article> Articles {get; set;}
    public class DbSet<Category> Categories {get; set;}
}

您不必提及连接点-table,entity framework 会自动为您生成它,但如果您需要 [=18],则不必将其用于连接=] 与他们的 Categories,或 Categories 与他们的 Articles,只需使用 ICollections

注意:由于 Categories 不是 Category 的复数形式,您必须告诉 entity framework 正确的 table 名称。超出这个问题的范围。

删除一篇文章,但保留它所属的所有类别:

using (var dbContext = new MyDbContext(...))
{
    Article articleToRemove = ...
    dbContext.Articles.Remove(articleToRemove);
    dbContext.SaveChanges();
}

Entity framework 将自动执行正确的连接,并从每个类别中删除 articleToRemove。但是,不会删除类别。

事实上,类别 table 在内部根本没有改变。所有具有 Article.Id 的记录将从联结 table.

中删除