【问题标题】:Cascade delete in one to one relationship一对一关系中的级联删除
【发布时间】:2018-04-26 07:20:30
【问题描述】:

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

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

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

这是我的模型的实体

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

【问题讨论】:

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


    【解决方案1】:

    你是对的,这是ArticleCategory之间的多对多关系:一个Article有零个或多个Categories,每个Category可以被零个或多个@使用987654326@.

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

    同样,如果你删除了Category,实体框架也不能自动删除属于这个类别的Articles

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

    如果你删除了Book,那么实体框架就知道它应该自动删除Book中的所有Pages,这些都是Pages,外键为BookId。如果实体框架只删除Book,那么我们将有一堆Pages,其外键值指向一个不存在的Book。所以在一对多关系中,实体框架可以级联删除。

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

    从好的方面来说,您可以删除Category 的最后一个Article,并保持Category 不变。明天你可以添加一个新的Article 使用这个Category

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

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

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

    您不必提及联结表,实体框架会自动为您生成,但如果您想要 Articles 与他们的 Categories 或 @987654358 进行连接,则不必使用它@ 与他们的Articles,只需使用ICollections

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

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-07-27
      • 1970-01-01
      • 2016-01-17
      相关资源
      最近更新 更多