ef6 и каскадное удаление - PullRequest
       3

ef6 и каскадное удаление

0 голосов
/ 07 января 2019

Я обнаружил небольшую проблему в 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 -igration 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 голосов
/ 07 января 2019

Может быть, эта документация вводит в заблуждение или просто неверна. Официальная документация говорит вам следующее:

Вы можете настроить каскадное удаление для отношения с помощью метода WillCascadeOnDelete. Если внешний ключ на зависимом объекте не имеет значения null, то Code First устанавливает каскадное удаление в отношении. Если внешний ключ на зависимом объекте имеет значение NULL, Code First не устанавливает каскадное удаление в отношении, и при удалении принципала внешний ключ будет иметь значение NULL.

Таким образом, в основном говорится, что поведение по умолчанию зависит от обнуляемости вашего внешнего ключа и не , разрешающей каскадное удаление для всех отношений по умолчанию, как указано в предоставленной вами ссылке *. * 1013

Я вижу то же самое в вашем случае:

  • В первом случае CategoryId обнуляется, поэтому каскадное удаление не будет использоваться по умолчанию, поэтому вам необходимо включить его явно
  • Во втором случае QuestionId не имеет значения nullable, в результате чего по умолчанию используется каскадное удаление , но вы можете явно отключить его (что вы не пытались, насколько я понимаю, вы только пытались включить его, но он уже был включен по умолчанию)

Что касается того, почему нет явного каскадного удаления в другом случае, я не уверен, но я думаю, что это может быть и по умолчанию в SQL, поэтому WillCascadeOnDelete(true) просто ничего не меняет с любой стороны. Тем не менее, вы можете получить другие результаты, если вы попробуете WillCascadeOnDelete(false), который должен переопределить поведение по умолчанию на основе документации.

0 голосов
/ 08 января 2019

Итак, это беспокоило меня; Я решил изменить свой 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 back:

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 для создания каскадного удаления. Если вы хотите, вам нужно указать это при создании. Это должно предотвратить мою проблему с вами. Но если это произойдет, просто отключите его и включите снова при следующей миграции, и это решит вашу проблему.

0 голосов
/ 07 января 2019

Насколько я знаю, EF обрабатывает отношения и каскадное удаление через следующие настройки конфигурации:

Не делать каскадное удаление, если:

  • это явно указано .WillCascadeOnDelete(false)
  • с необязательным отношением, т. Е. .WithOptional()

Do делать каскадное удаление, если:

  • это явно указано .WillCascadeOnDelete(true)
  • с обязательным соотношением, т. Е. .WithRequired(/*subject*/)

Примечание: они также могут быть вызваны аннотациями данных, например; [RequiredAttribute], или, необязательный вариант; используя Nullable<Type>

Теперь в вашем ограничении есть:

ALTER TABLE [dbo]. [Ответы] С CHECK ADD CONSTRAINT [FK_dbo.Answers_dbo.Questions_QuestionId] FOREIGN KEY ([QuestionId]) ССЫЛКИ [dbo]. [Вопросы] ([Id]) GO

Но это относится к ответам, а не к вопросам. Итак, я думаю, что ограничение действует:

Вопрос может быть без ответов.

Я соберусь, если вы проверите ограничение на questions, вы обнаружите, что каскадное удаление включено.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...