级联删除一对一关系

时间:2017-11-13 14:57:00

标签: entity-framework model ef-fluent-api cascading-deletes

我希望以1:1的关系进行级联删除,其中我将多个实体引用为一个。问题导致数据库更新错误

  

介绍FOREIGN KEY约束' FK_dbo.CategoryArticles_dbo.Articles_Article_Id'在表格' CategoryArticles'可能会导致循环或多个级联路径。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY约束。

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

以下是我的模特实体

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();

1 个答案:

答案 0 :(得分:1)

你是对的,这是ArticleCategory之间的多对多关系:一个Article有零个或多个Categories,每个{{1}可以由零个或多个Category使用。

如果您删除了Articles,则无法自动删除其Article,因为其他Categories可能会使用Category,即使它现在还没有使用,实体框架不知道你明天是否想要使用它。毕竟,您指定或更多Articles可能会使用每个Category

同样,如果您删除Articles,则实体框架无法自动删除属于此类别的Category

这与一对多的关系不同。例如,如果您与Articles及其Book之间存在一对多关系,那么每个Pages都有零个或多个Book以及每个Pages }只属于一个Page

如果您删除Book,则实体框架知道它应该自动删除Book的所有Pages,这些Book都是Pages的外键{{ 1}}。如果实体框架只删除BookId,那么我们会有一堆Book外键值指向不存在的Pages。因此,在一对多关系中,实体框架可以在删除时级联。

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

从好的方面来说,您可以删除Book的最后Article,并保持Category完好无损。明天您可以添加使用此Category的新Article

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

符合标准命名约定的多对多:

Category

不要忘记宣布您的ICollections虚拟!

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;}
    ...
}

您不必提及联结表,实体框架会自动为您提供,但如果您希望class MyDbContext : DbContext { public class DbSet<Article> Articles {get; set;} public class DbSet<Category> Categories {get; set;} } 使用Articles,则不必将其用于联接{1}}或Categories及其Categories,只需使用Articles

注意:由于Categories不是预期的Category复数,因此您必须告诉实体框架正确的表名。超出了这个问题的范围。

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

ICollections

实体框架将自动执行正确的连接,并从每个类别中删除articleToRemove。但是,类别不会被删除。

事实上,类别表内部根本没有变化。带有Article.Id的所有记录都将从联结表中删除。