【问题标题】:ef6 and cascading deleteef6 和级联删除
【发布时间】:2019-01-07 10:36:21
【问题描述】:

我在 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 约束冲突

经过调查,它正在抱怨 Answers 表。以下是 QuestionAnswer 模型:

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。 我认为大多数都是默认设置的,在这种情况下,它实际上不会在迁移中生成任何代码。 但是当我检查我的任何表时,只有一些表启用了级联删除,我不明白为什么....

【问题讨论】:

    标签: c# entity-framework


    【解决方案1】:

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

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

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

    做级联删除如果:

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

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

    现在,在你的约束中有:

    ALTER TABLE [dbo].[Answers] WITH CHECK ADD CONSTRAINT [FK_dbo.Answers_dbo.Questions_QuestionId] FOREIGN KEY([QuestionId]) 参考文献 [dbo].[问题] ([Id]) 去吧

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

    一个问题可以没有答案。

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

    【讨论】:

    • 我明白你在说什么,但你可以为关于类别的问题提出相同的观点。一个类别可以在没有任何问题的情况下存在,但它仍然强制级联删除,因为没有类别的问题就无法存在。同样,没有问题就不可能存在答案,因此它应该遵循相同的规则,但事实并非如此。
    【解决方案2】:

    也许是文档具有误导性或完全错误。 official documentation 告诉你:

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

    所以它基本上说默认行为取决于您的外键的可空性,并且默认情况下对所有关系启用级联删除,如链接中所述你提供的。

    我在你的情况下看到了同样的情况:

    • 在第一种情况下,CategoryId 可以为空,从而导致默认情况下不使用级联删除,因此您需要显式启用它
    • 在第二种情况下,QuestionId 不可为空,因此默认情况下会使用级联删除但您可以显式禁用它(据我了解,您尚未尝试过) ,你只是尝试启用它,但它已经默认启用)

    至于为什么在另一种情况下没有显式级联删除,我不确定,但我认为它在 SQL 中也可能是默认设置,因此WillCascadeOnDelete(true) 根本不会改变任何方面的任何内容。但是,如果您尝试 WillCascadeOnDelete(false),您可能会得到不同的结果,这应该会根据文档覆盖默认行为。

    【讨论】:

    • 我假设您的意思是 CriteriaId 可以为空?因为QuestionId 不是。我已经设置了CriteriaId 来强制级联删除,这很好。但与 Answers 一样,即使将 WillCascadeOnDelete 设置为 true,Attributes 似乎也没有启用级联删除。此外,AttributeId/AnswerId 是必需的,因此它应该启用级联删除,但它没有。我已更新我的问题以完整显示我的 DbContext
    • @r3plica 抱歉,我的意思是CategoryId,因为第一个例子是关于Question-to-Category 关系。相应地编辑了我的答案。
    • Coolio,它仍然存在。标准确实有级联删除,似乎取自WillCascadeOnDelete。我仍然无法理解为什么其他人不是......
    • @r3plica 我的意思是它可能是 EntityFramework 和 SQL 服务器的默认行为,因此它不会添加显式语句。但是,我不确定这一点,需要进行实验。您是否尝试过 WillCascadeOnDelete(false) 只是为了看看它是否可以改变可能的默认行为?
    • 这似乎不是默认行为,但我找到了解决方案
    【解决方案3】:

    所以,这让我很困扰;我决定改变我的 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 来创建级联删除。如果你想要它,你需要在创建时指定它。这应该可以避免我的问题发生在你身上。 但是,如果确实如此,只需将其禁用并在下次迁移时重新启用即可解决您的问题。

    【讨论】:

      猜你喜欢
      • 2015-09-21
      • 2018-03-06
      • 1970-01-01
      • 1970-01-01
      • 2015-10-06
      • 2014-09-28
      • 1970-01-01
      • 1970-01-01
      • 2015-04-24
      相关资源
      最近更新 更多