ef6和级联删除

时间:2019-01-07 10:36:22

标签: c# entity-framework

我在EntityFramework 6中发现了一个小问题,我不确定这是我做错了什么。

默认情况下,我认为应按以下说明启用它: http://www.entityframeworktutorial.net/code-first/cascade-delete-in-code-first.aspx

但是我在应用程序中发现了并非如此的实例。 我有这个模型:

public class Category
{
    public string Id { get; set; }
    [Required] [MaxLength(100)] [Index(IsUnique = true)] public string Name { get; set; }
    [MaxLength(2083)] public string Image { get; set; }
    public bool Live { get; set; }

    public IList<Criteria> Criteria { get; set; }
    public IList<Feed> Feeds { get; set; }
    public IList<Sortation> Sortations { get; set; }
    public IList<Quote> Quotes { get; set; }
    public IList<Question> Questions { get; set; }
}

它没有级联删除功能可解决问题,因此我将 DbContext 更新为:

modelBuilder.Entity<Category>().HasMany(m => m.Questions).WithOptional().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);

当我运行update-database时,我看到约束现在是正确的:

ALTER TABLE [dbo].[Questions]  WITH CHECK ADD  CONSTRAINT [FK_dbo.Questions_dbo.Categories_CategoryId] FOREIGN KEY([CategoryId])
REFERENCES [dbo].[Categories] ([Id])
ON DELETE CASCADE
GO

我试图删除类别并收到错误消息:

  

DELETE语句与REFERENCE约束冲突

经调查,这是关于答案表的抱怨。这是问题答案模型:

public class Question : Key
{
    public string CategoryId { get; set; }
    [Required, MaxLength(255)] public string Text { get; set; }
    [MaxLength(255)] public string AltText { get; set; }
    public int Order { get; set; }
    public int Priority { get; set; }
    public QuestionType Type { get; set; }

    public IList<Answer> Answers { get; set; }
}

public class Answer: Key
{
    public int QuestionId { get; set; }
    public int? CriteriaId { get; set; }
    [Required] [MaxLength(255)] public string Text { get; set; }
    public int Order { get; set; }
    public int Priority { get; set; }
    [MaxLength(2083)] public string Image { get; set; }

    public Criteria Criteria { get; set; }
    public Question Question { get; set; }
    public Scenario Scenario { get; set; }
    public IList<AnswerFormula> Formulas { get; set; }
    public IList<Image> Images { get; set; }
}

映射看起来像这样:

modelBuilder.Entity<Question>().HasMany(m => m.Answers).WithRequired(m => m.Question).HasForeignKey(m => m.QuestionId)

但是,如果我检查约束,我会看到:

ALTER TABLE [dbo].[Answers]  WITH CHECK ADD  CONSTRAINT [FK_dbo.Answers_dbo.Questions_QuestionId] FOREIGN KEY([QuestionId])
REFERENCES [dbo].[Questions] ([Id])
GO

我认为错了,我认为应该是:

ALTER TABLE [dbo].[Answers]  WITH CHECK ADD  CONSTRAINT [FK_dbo.Answers_dbo.Questions_QuestionId] FOREIGN KEY([QuestionId])
REFERENCES [dbo].[Questions] ([Id])
ON DELETE CASCADE
GO

所以我将映射更改为此:

modelBuilder.Entity<Question>().HasMany(m => m.Answers).WithRequired(m => m.Question).HasForeignKey(m => m.QuestionId).WillCascadeOnDelete(true);

并运行'add-migration AnswerCascadeDelete`,它告诉我没有任何变化。...

有人知道为什么吗?


作为更新,这是我的 DbContext

public class DatabaseContext : IdentityDbContext<User>
{
    public DatabaseContext()
        : base("DefaultConnection")
    {
        Database.CommandTimeout = 900;
        Database.Log = s => Debug.WriteLine(s);
        Configuration.LazyLoadingEnabled = false;
    }

    public DbSet<Feed> Feeds { get; set; }

    public DbSet<Organisation> Organisations { get; set; }
    public DbSet<Category> Categories { get; set; }
    public DbSet<Criteria> Criteria { get; set; }
    public DbSet<Attribute> Attributes { get; set; }
    public DbSet<AttributeFormula> CriteriaForumlas { get; set; }

    public DbSet<AttributeType> AttributeTypes { get; set; }
    public DbSet<AttributeOperation> AttributeOperations { get; set; }
    public DbSet<Scenario> Scenarios { get; set; }
    public DbSet<Question> Questions { get; set; }
    public DbSet<Answer> Answers { get; set; }
    public DbSet<AnswerFormula> AnswerForumlas { get; set; }

    public DbSet<Quote> Quotes { get; set; }

    public DbSet<Claim> Claims { get; set; }
    public DbSet<Client> Clients { get; set; }
    public DbSet<RefreshToken> RefreshTokens { get; set; }

    public DbSet<Search> Searches { get; set; }
    public DbSet<Charge> Charges { get; set; }
    public DbSet<Exclusion> Exclusions { get; set; }
    public DbSet<Sortation> Sortations { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        // Table renames
        modelBuilder.Entity<Criteria>().ToTable("Criteria");
        modelBuilder.Entity<IdentityRole>().ToTable("Roles");
        modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
        modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
        modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");
        modelBuilder.Entity<ImageText>().ToTable("ImageText");

        // One to One
        modelBuilder.Entity<Attribute>().HasOptional(m => m.Type).WithRequired(m => m.Attribute).WillCascadeOnDelete(false);
        modelBuilder.Entity<Attribute>().HasOptional(m => m.Operation).WithRequired(m => m.Attribute).WillCascadeOnDelete(false);
        modelBuilder.Entity<Answer>().HasOptional(m => m.Scenario).WithRequired(m => m.Answer).WillCascadeOnDelete(false);
        modelBuilder.Entity<Answer>().HasOptional(m => m.Criteria).WithMany().HasForeignKey(m => m.CriteriaId).WillCascadeOnDelete(false);

        // One to Many  
        modelBuilder.Entity<Criteria>().HasMany(m => m.Attributes).WithRequired().HasForeignKey(m => m.CriteriaId).WillCascadeOnDelete(true);
        modelBuilder.Entity<IdentityRole>().HasMany(m => m.Users).WithRequired().HasForeignKey(m => m.RoleId).WillCascadeOnDelete(false);
        modelBuilder.Entity<Organisation>().HasMany(m => m.Feeds).WithRequired().HasForeignKey(m => m.OrganisationId).WillCascadeOnDelete(true);
        modelBuilder.Entity<Organisation>().HasMany(m => m.Users).WithRequired().HasForeignKey(m => m.OrganisationId).WillCascadeOnDelete(true);
        modelBuilder.Entity<Question>().HasMany(m => m.Answers).WithRequired(m => m.Question).HasForeignKey(m => m.QuestionId).WillCascadeOnDelete(true);

        modelBuilder.Entity<Category>().HasMany(m => m.Sortations).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);
        modelBuilder.Entity<Category>().HasMany(m => m.Criteria).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);
        modelBuilder.Entity<Category>().HasMany(m => m.Feeds).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);
        modelBuilder.Entity<Category>().HasMany(m => m.Questions).WithOptional().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);
        modelBuilder.Entity<Category>().HasMany(m => m.Quotes).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);

        modelBuilder.Entity<User>().HasMany(m => m.Searches).WithRequired().HasForeignKey(m => m.UserId).WillCascadeOnDelete(true);
        modelBuilder.Entity<User>().HasMany(m => m.Charges).WithRequired().HasForeignKey(m => m.UserId).WillCascadeOnDelete(true);
        modelBuilder.Entity<Answer>().HasMany(m => m.Images).WithRequired().HasForeignKey(m => m.AnswerId).WillCascadeOnDelete(true);
        modelBuilder.Entity<Image>().HasMany(m => m.ImageText).WithRequired().HasForeignKey(m => m.ImageId).WillCascadeOnDelete(true);

        modelBuilder.Entity<Attribute>().HasMany(m => m.Formulas).WithRequired().HasForeignKey(m => m.AttributeId).WillCascadeOnDelete(true);
        modelBuilder.Entity<Answer>().HasMany(m => m.Formulas).WithRequired().HasForeignKey(m => m.AnswerId).WillCascadeOnDelete(true);

        // Create our primary keys
        modelBuilder.Entity<IdentityUserLogin>().HasKey(m => m.UserId);
        modelBuilder.Entity<IdentityRole>().HasKey(m => m.Id);
        modelBuilder.Entity<IdentityUserRole>().HasKey(m => new {m.RoleId, m.UserId});
        modelBuilder.Entity<AttributeOperation>().HasKey(m => m.AttributeId);
        modelBuilder.Entity<AttributeType>().HasKey(m => m.AttributeId);
        modelBuilder.Entity<Scenario>().HasKey(m => m.AnswerId);
    }
}

如您所见,我已经在所有关系上显式设置了WillCascadeOnDelete。 我认为大多数将默认设置,在这种情况下,它实际上不会在迁移中生成任何代码。 但是当我检查任何一个表时,只有一些表启用了级联删除,我不明白为什么。...

3 个答案:

答案 0 :(得分:0)

据我所知,EF通过以下配置设置来处理关系和级联删除:

不要在以下情况下级联删除:

  • .WillCascadeOnDelete(false)
  • 明确声明
  • 具有可选关系,即:.WithOptional()

执行,如果发生以下情况,请进行级联删除:

  • .WillCascadeOnDelete(true)
  • 明确声明
  • 具有必需的关系,即:.WithRequired(/*subject*/)

注意:这些也可以由数据注释触发,例如; [RequiredAttribute],或可选变体;使用Nullable<Type>

现在,在您的约束中:

  

ALTER TABLE [dbo]。[答案]带有检查添加约束[FK_dbo.Answers_dbo.Questions_QuestionId]外键([QuestionId])   参考[dbo]。[问题]([Id])   开始

但这是指答案,而不是问题。所以,我认为约束是有效的:

一个问题可能没有答案。

如果您检查questions上的约束,我将收集并发现级联删除已启用。

答案 1 :(得分:0)

可能是文档具有误导性或完全是错误的。 official documentation告诉您:

  

您可以使用WillCascadeOnDelete方法在关系上配置级联删除。如果从属实体上的外键不可为空,则Code First将在关系上设置级联删除。如果从属实体上的外键可为空,则Code First不会在关系上设置级联删除,并且当删除主体时,外键将设置为null。

因此,它基本上说默认行为取决于外键的可空性,并且 not 默认情况下启用所有链接上的级联删除,因为它在链接中指出您提供的。

在您的情况下,我看到的完全相同:

  • 在第一种情况下,CategoryId可为空,因此默认情况下不使用级联删除,因此您需要显式启用它
  • 在第二种情况下,QuestionId不能为空,因此默认情况下会使用级联删除,但是您可以显式禁用它(到目前为止,您还没有尝试过)我了解,您只是尝试启用它,但默认情况下已将其启用)

对于在其他情况下为什么没有显式级联删除的原因,我不确定,但是我认为它在SQL中也可能是默认值,因此WillCascadeOnDelete(true)根本没有任何改变。但是,如果尝试使用WillCascadeOnDelete(false),则可能会得到不同的结果,该{{1}}应该会覆盖基于文档的默认行为。

答案 2 :(得分:0)

所以,这让我很烦;我决定更改我的 DbContext 。首先,我禁用所有级联删除,然后像这样更新数据库:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Table renames
    modelBuilder.Entity<Criteria>().ToTable("Criteria");
    modelBuilder.Entity<IdentityRole>().ToTable("Roles");
    modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
    modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
    modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");

    // One to One
    modelBuilder.Entity<Attribute>().HasOptional(m => m.Type).WithRequired(m => m.Attribute).WillCascadeOnDelete(false);
    modelBuilder.Entity<Attribute>().HasOptional(m => m.Operation).WithRequired(m => m.Attribute).WillCascadeOnDelete(false);
    modelBuilder.Entity<Answer>().HasOptional(m => m.Scenario).WithRequired(m => m.Answer).WillCascadeOnDelete(false);
    modelBuilder.Entity<Answer>().HasOptional(m => m.Criteria).WithMany().HasForeignKey(m => m.CriteriaId).WillCascadeOnDelete(false);

    // One to Many  
    modelBuilder.Entity<Criteria>().HasMany(m => m.Attributes).WithRequired().HasForeignKey(m => m.CriteriaId).WillCascadeOnDelete(false);
    modelBuilder.Entity<IdentityRole>().HasMany(m => m.Users).WithRequired().HasForeignKey(m => m.RoleId).WillCascadeOnDelete(false);
    modelBuilder.Entity<Organisation>().HasMany(m => m.Feeds).WithRequired().HasForeignKey(m => m.OrganisationId).WillCascadeOnDelete(false);
    modelBuilder.Entity<Organisation>().HasMany(m => m.Users).WithRequired().HasForeignKey(m => m.OrganisationId).WillCascadeOnDelete(false);
    modelBuilder.Entity<Question>().HasMany(m => m.Answers).WithRequired(m => m.Question).HasForeignKey(m => m.QuestionId).WillCascadeOnDelete(false);

    modelBuilder.Entity<Category>().HasMany(m => m.Sortations).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(false);
    modelBuilder.Entity<Category>().HasMany(m => m.Criteria).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(false);
    modelBuilder.Entity<Category>().HasMany(m => m.Feeds).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(false);
    modelBuilder.Entity<Category>().HasMany(m => m.Questions).WithOptional().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(false);
    modelBuilder.Entity<Category>().HasMany(m => m.Quotes).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(false);

    modelBuilder.Entity<User>().HasMany(m => m.Searches).WithRequired().HasForeignKey(m => m.UserId).WillCascadeOnDelete(false);
    modelBuilder.Entity<User>().HasMany(m => m.Charges).WithRequired().HasForeignKey(m => m.UserId).WillCascadeOnDelete(false);

    modelBuilder.Entity<Attribute>().HasMany(m => m.Formulas).WithRequired().HasForeignKey(m => m.AttributeId).WillCascadeOnDelete(false);
    modelBuilder.Entity<Answer>().HasMany(m => m.Formulas).WithRequired().HasForeignKey(m => m.AnswerId).WillCascadeOnDelete(false);

    // Create our primary keys
    modelBuilder.Entity<IdentityUserLogin>().HasKey(m => m.UserId);
    modelBuilder.Entity<IdentityRole>().HasKey(m => m.Id);
    modelBuilder.Entity<IdentityUserRole>().HasKey(m => new {m.RoleId, m.UserId});
    modelBuilder.Entity<AttributeOperation>().HasKey(m => m.AttributeId);
    modelBuilder.Entity<AttributeType>().HasKey(m => m.AttributeId);
    modelBuilder.Entity<Scenario>().HasKey(m => m.AnswerId);
}

运行此命令时,它实际上正确地更新了外键。我可以看到这个:

public partial class DisableCascadeDelete : DbMigration
{
    public override void Up()
    {
        DropForeignKey("dbo.AnswerFormulas", "AnswerId", "dbo.Answers");
        DropForeignKey("dbo.Images", "AnswerId", "dbo.Answers");
        DropForeignKey("dbo.Answers", "QuestionId", "dbo.Questions");
        DropForeignKey("dbo.Attributes", "CriteriaId", "dbo.Criteria");
        DropForeignKey("dbo.AttributeFormulas", "AttributeId", "dbo.Attributes");
        DropForeignKey("dbo.ImageText", "ImageId", "dbo.Images");
        DropForeignKey("dbo.Criteria", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Feeds", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Questions", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Quotes", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Sortations", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Feeds", "OrganisationId", "dbo.Organisations");
        DropForeignKey("dbo.Users", "OrganisationId", "dbo.Organisations");
        DropForeignKey("dbo.Charges", "UserId", "dbo.Users");
        DropForeignKey("dbo.Searches", "UserId", "dbo.Users");
        AddForeignKey("dbo.AnswerFormulas", "AnswerId", "dbo.Answers", "Id");
        AddForeignKey("dbo.Images", "AnswerId", "dbo.Answers", "Id");
        AddForeignKey("dbo.Answers", "QuestionId", "dbo.Questions", "Id");
        AddForeignKey("dbo.Attributes", "CriteriaId", "dbo.Criteria", "Id");
        AddForeignKey("dbo.AttributeFormulas", "AttributeId", "dbo.Attributes", "Id");
        AddForeignKey("dbo.ImageText", "ImageId", "dbo.Images", "Id");
        AddForeignKey("dbo.Criteria", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.Feeds", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.Questions", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.Quotes", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.Sortations", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.Feeds", "OrganisationId", "dbo.Organisations", "Id");
        AddForeignKey("dbo.Users", "OrganisationId", "dbo.Organisations", "Id");
        AddForeignKey("dbo.Charges", "UserId", "dbo.Users", "Id");
        AddForeignKey("dbo.Searches", "UserId", "dbo.Users", "Id");
    }

    public override void Down()
    {
        DropForeignKey("dbo.Searches", "UserId", "dbo.Users");
        DropForeignKey("dbo.Charges", "UserId", "dbo.Users");
        DropForeignKey("dbo.Users", "OrganisationId", "dbo.Organisations");
        DropForeignKey("dbo.Feeds", "OrganisationId", "dbo.Organisations");
        DropForeignKey("dbo.Sortations", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Quotes", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Questions", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Feeds", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Criteria", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.ImageText", "ImageId", "dbo.Images");
        DropForeignKey("dbo.AttributeFormulas", "AttributeId", "dbo.Attributes");
        DropForeignKey("dbo.Attributes", "CriteriaId", "dbo.Criteria");
        DropForeignKey("dbo.Answers", "QuestionId", "dbo.Questions");
        DropForeignKey("dbo.Images", "AnswerId", "dbo.Answers");
        DropForeignKey("dbo.AnswerFormulas", "AnswerId", "dbo.Answers");
        AddForeignKey("dbo.Searches", "UserId", "dbo.Users", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Charges", "UserId", "dbo.Users", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Users", "OrganisationId", "dbo.Organisations", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Feeds", "OrganisationId", "dbo.Organisations", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Sortations", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Quotes", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Questions", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Feeds", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Criteria", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.ImageText", "ImageId", "dbo.Images", "Id", cascadeDelete: true);
        AddForeignKey("dbo.AttributeFormulas", "AttributeId", "dbo.Attributes", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Attributes", "CriteriaId", "dbo.Criteria", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Answers", "QuestionId", "dbo.Questions", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Images", "AnswerId", "dbo.Answers", "Id", cascadeDelete: true);
        AddForeignKey("dbo.AnswerFormulas", "AnswerId", "dbo.Answers", "Id", cascadeDelete: true);
    }
}

我能看到的是正确的。然后,我将 DbContext 改回原来的位置,然后创建了一个新迁移:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // Table renames
    modelBuilder.Entity<Criteria>().ToTable("Criteria");
    modelBuilder.Entity<IdentityRole>().ToTable("Roles");
    modelBuilder.Entity<IdentityUserRole>().ToTable("UserRoles");
    modelBuilder.Entity<IdentityUserClaim>().ToTable("UserClaims");
    modelBuilder.Entity<IdentityUserLogin>().ToTable("UserLogins");

    // One to One
    modelBuilder.Entity<Attribute>().HasOptional(m => m.Type).WithRequired(m => m.Attribute).WillCascadeOnDelete(false);
    modelBuilder.Entity<Attribute>().HasOptional(m => m.Operation).WithRequired(m => m.Attribute).WillCascadeOnDelete(false);
    modelBuilder.Entity<Answer>().HasOptional(m => m.Scenario).WithRequired(m => m.Answer).WillCascadeOnDelete(false);
    modelBuilder.Entity<Answer>().HasOptional(m => m.Criteria).WithMany().HasForeignKey(m => m.CriteriaId).WillCascadeOnDelete(false);

    // One to Many  
    modelBuilder.Entity<Criteria>().HasMany(m => m.Attributes).WithRequired().HasForeignKey(m => m.CriteriaId).WillCascadeOnDelete(true);
    modelBuilder.Entity<IdentityRole>().HasMany(m => m.Users).WithRequired().HasForeignKey(m => m.RoleId).WillCascadeOnDelete(false);
    modelBuilder.Entity<Organisation>().HasMany(m => m.Feeds).WithRequired().HasForeignKey(m => m.OrganisationId).WillCascadeOnDelete(true);
    modelBuilder.Entity<Organisation>().HasMany(m => m.Users).WithRequired().HasForeignKey(m => m.OrganisationId).WillCascadeOnDelete(true);
    modelBuilder.Entity<Question>().HasMany(m => m.Answers).WithRequired(m => m.Question).HasForeignKey(m => m.QuestionId).WillCascadeOnDelete(true);

    modelBuilder.Entity<Category>().HasMany(m => m.Sortations).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);
    modelBuilder.Entity<Category>().HasMany(m => m.Criteria).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);
    modelBuilder.Entity<Category>().HasMany(m => m.Feeds).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);
    modelBuilder.Entity<Category>().HasMany(m => m.Questions).WithOptional().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);
    modelBuilder.Entity<Category>().HasMany(m => m.Quotes).WithRequired().HasForeignKey(m => m.CategoryId).WillCascadeOnDelete(true);

    modelBuilder.Entity<User>().HasMany(m => m.Searches).WithRequired().HasForeignKey(m => m.UserId).WillCascadeOnDelete(true);
    modelBuilder.Entity<User>().HasMany(m => m.Charges).WithRequired().HasForeignKey(m => m.UserId).WillCascadeOnDelete(true);

    modelBuilder.Entity<Attribute>().HasMany(m => m.Formulas).WithRequired().HasForeignKey(m => m.AttributeId).WillCascadeOnDelete(true);
    modelBuilder.Entity<Answer>().HasMany(m => m.Formulas).WithRequired().HasForeignKey(m => m.AnswerId).WillCascadeOnDelete(true);

    // Create our primary keys
    modelBuilder.Entity<IdentityUserLogin>().HasKey(m => m.UserId);
    modelBuilder.Entity<IdentityRole>().HasKey(m => m.Id);
    modelBuilder.Entity<IdentityUserRole>().HasKey(m => new {m.RoleId, m.UserId});
    modelBuilder.Entity<AttributeOperation>().HasKey(m => m.AttributeId);
    modelBuilder.Entity<AttributeType>().HasKey(m => m.AttributeId);
    modelBuilder.Entity<Scenario>().HasKey(m => m.AnswerId);
}

哪个生成的:

public partial class EnableCascadeDelete : DbMigration
{
    public override void Up()
    {
        DropForeignKey("dbo.ImageText", "ImageId", "dbo.Images");
        DropForeignKey("dbo.Images", "AnswerId", "dbo.Answers");
        DropForeignKey("dbo.AnswerFormulas", "AnswerId", "dbo.Answers");
        DropForeignKey("dbo.Answers", "QuestionId", "dbo.Questions");
        DropForeignKey("dbo.Attributes", "CriteriaId", "dbo.Criteria");
        DropForeignKey("dbo.AttributeFormulas", "AttributeId", "dbo.Attributes");
        DropForeignKey("dbo.Criteria", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Feeds", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Questions", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Quotes", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Sortations", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Feeds", "OrganisationId", "dbo.Organisations");
        DropForeignKey("dbo.Users", "OrganisationId", "dbo.Organisations");
        DropForeignKey("dbo.Charges", "UserId", "dbo.Users");
        DropForeignKey("dbo.Searches", "UserId", "dbo.Users");
        DropIndex("dbo.Images", new[] { "AnswerId" });
        DropIndex("dbo.ImageText", new[] { "ImageId" });
        AddForeignKey("dbo.AnswerFormulas", "AnswerId", "dbo.Answers", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Answers", "QuestionId", "dbo.Questions", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Attributes", "CriteriaId", "dbo.Criteria", "Id", cascadeDelete: true);
        AddForeignKey("dbo.AttributeFormulas", "AttributeId", "dbo.Attributes", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Criteria", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Feeds", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Questions", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Quotes", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Sortations", "CategoryId", "dbo.Categories", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Feeds", "OrganisationId", "dbo.Organisations", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Users", "OrganisationId", "dbo.Organisations", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Charges", "UserId", "dbo.Users", "Id", cascadeDelete: true);
        AddForeignKey("dbo.Searches", "UserId", "dbo.Users", "Id", cascadeDelete: true);
        DropTable("dbo.ImageText");
        DropTable("dbo.Images");
    }

    public override void Down()
    {
        CreateTable(
            "dbo.ImageText",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    ImageId = c.Int(nullable: false),
                    Text = c.String(),
                    Delay = c.Int(nullable: false),
                })
            .PrimaryKey(t => t.Id);

        CreateTable(
            "dbo.Images",
            c => new
                {
                    Id = c.Int(nullable: false, identity: true),
                    AnswerId = c.Int(nullable: false),
                    Url = c.String(),
                })
            .PrimaryKey(t => t.Id);

        DropForeignKey("dbo.Searches", "UserId", "dbo.Users");
        DropForeignKey("dbo.Charges", "UserId", "dbo.Users");
        DropForeignKey("dbo.Users", "OrganisationId", "dbo.Organisations");
        DropForeignKey("dbo.Feeds", "OrganisationId", "dbo.Organisations");
        DropForeignKey("dbo.Sortations", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Quotes", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Questions", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Feeds", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.Criteria", "CategoryId", "dbo.Categories");
        DropForeignKey("dbo.AttributeFormulas", "AttributeId", "dbo.Attributes");
        DropForeignKey("dbo.Attributes", "CriteriaId", "dbo.Criteria");
        DropForeignKey("dbo.Answers", "QuestionId", "dbo.Questions");
        DropForeignKey("dbo.AnswerFormulas", "AnswerId", "dbo.Answers");
        CreateIndex("dbo.ImageText", "ImageId");
        CreateIndex("dbo.Images", "AnswerId");
        AddForeignKey("dbo.Searches", "UserId", "dbo.Users", "Id");
        AddForeignKey("dbo.Charges", "UserId", "dbo.Users", "Id");
        AddForeignKey("dbo.Users", "OrganisationId", "dbo.Organisations", "Id");
        AddForeignKey("dbo.Feeds", "OrganisationId", "dbo.Organisations", "Id");
        AddForeignKey("dbo.Sortations", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.Quotes", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.Questions", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.Feeds", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.Criteria", "CategoryId", "dbo.Categories", "Id");
        AddForeignKey("dbo.AttributeFormulas", "AttributeId", "dbo.Attributes", "Id");
        AddForeignKey("dbo.Attributes", "CriteriaId", "dbo.Criteria", "Id");
        AddForeignKey("dbo.Answers", "QuestionId", "dbo.Questions", "Id");
        AddForeignKey("dbo.AnswerFormulas", "AnswerId", "dbo.Answers", "Id");
        AddForeignKey("dbo.Images", "AnswerId", "dbo.Answers", "Id");
        AddForeignKey("dbo.ImageText", "ImageId", "dbo.Images", "Id");
    }
}

如您所见,每个外键现在都具有:

AddForeignKey("dbo.AnswerFormulas", "AnswerId", "dbo.Answers", "Id", cascadeDelete: true);

因此,它明确设置了从未出现过的cascadeDelete选项。

那么,我的结论是什么? 看来,当首先设置数据库代码时,您不能也不应该依赖EntityFramework创建级联删除。如果需要,则需要在创建时指定它。这应该避免我的问题发生在您身上。 但是,如果确实如此,只需禁用它,然后在下一次迁移时重新启用它即可解决您的问题。