4
votes

ef6 et suppression en cascade

J'ai trouvé un petit problème dans EntityFramework 6 et je ne sais pas si c'est quelque chose que j'ai mal fait.

Par défaut, je pense qu'il devrait être activé comme indiqué ici: http://www.entityframeworktutorial.net/code- first / cascade-delete-in-code-first.aspx

Mais j'ai trouvé des instances dans mon application où ce n'est pas le cas. J'ai ce modèle:

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

Il n'y avait pas de suppression en cascade pour les questions, j'ai donc mis à jour mon DbContext comme suit:

XXX

Et quand j'ai exécuté update-database j'ai vu que la contrainte était maintenant correcte:

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

J'ai essayé pour supprimer une catégorie et une erreur s'est produite:

L'instruction DELETE était en conflit avec la contrainte REFERENCE

Après enquête, il se plaint au sujet du tableau Réponses . Voici les modèles Question et Answer :

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

Le mappage ressemblait à ceci:

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

Mais si j'inspecte la contrainte, je vois ceci:

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

Ce qui me semble faux, je pense que cela devrait être:

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

J'ai donc changé mon mappage pour ceci:

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

et exécuté 'add-migration AnswerCascadeDelete` et il m'a dit qu'il n'y avait pas changements ....

Est-ce que quelqu'un sait pourquoi?


En guise de mise à jour, voici mon DbContext

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

Comme vous pouvez le voir, j'ai explicitement défini WillCascadeOnDelete sur toutes les relations. Je pensais que la plupart seraient définis par défaut, et dans ce cas, cela ne génère en fait aucun code dans la migration. Mais lorsque je vérifie l'une de mes tables, seules certaines d'entre elles ont activé la suppression en cascade et je ne comprends pas pourquoi ....


0 commentaires

3 Réponses :


0
votes

Pour autant que je sache, EF traite les relations et la suppression en cascade via les paramètres de configuration suivants:

Ne pas de suppression en cascade si:

  • c'est explicitement indiqué par .WillCascadeOnDelete(false)
  • avec une relation optionnelle, c'est-à-dire: .WithOptional()

Effectuer une suppression en cascade si:

  • c'est explicitement indiqué par .WillCascadeOnDelete(true)
  • avec la relation requise, c'est-à-dire: .WithRequired(/*subject*/)

Remarque: ceux-ci peuvent également être déclenchés par des annotations de données, par exemple; [RequiredAttribute] , ou, la variante facultative; en utilisant Nullable

Maintenant, dans votre contrainte il y a:

ALTER TABLE [dbo]. [Answers] WITH CHECK ADD CONSTRAINT [FK_dbo.Answers_dbo.Questions_QuestionId] FOREIGN KEY ([QuestionId]) RÉFÉRENCES [dbo]. [Questions] ([Id]) ALLER

Mais cela renvoie aux réponses et non aux questions. Donc, je pense que la contrainte est valide:

Une question peut être sans réponse.

Je vais rassembler si vous vérifiez la contrainte sur les questions , vous trouverez la suppression en cascade activée.


1 commentaires

Je vois ce que vous dites, mais vous pourriez faire valoir le même point pour les questions sur les catégories. Une catégorie peut exister sans aucune question, mais elle applique toujours la suppression en cascade car une question ne peut pas exister sans catégorie. De même, une réponse ne peut pas exister sans question, elle doit donc suivre les mêmes règles, mais ce n'est pas le cas.



0
votes

C'est peut-être la documentation qui est trompeuse ou tout simplement erronée. La documentation officielle < / a> vous dit ceci:

Vous pouvez configurer la suppression en cascade sur une relation en utilisant la méthode WillCascadeOnDelete. Si une clé étrangère sur l'entité dépendante n'est pas nullable, alors Code First définit la suppression en cascade sur la relation. Si une clé étrangère sur l'entité dépendante est nullable, Code First ne définit pas la suppression en cascade sur la relation, et lorsque le principal est supprimé, la clé étrangère sera définie sur null.

Donc, cela dit en gros que le comportement par défaut dépend de la possibilité de nullité de votre clé étrangère et n'est pas d'activer la suppression en cascade sur toutes les relations par défaut comme indiqué dans le lien que vous avez fourni.

Je vois exactement la même chose dans votre cas:

  • Dans le premier cas, CategoryId est nullable, ce qui empêche l'utilisation de la suppression en cascade par défaut, vous devez donc l'activer explicitement
  • Dans le second cas, QuestionId n'est pas nullable, ce qui entraîne l'utilisation de la suppression en cascade par défaut mais vous pouvez la désactiver explicitement (ce que vous n'avez pas essayé, pour autant que je sache, vous avez seulement essayé de l'activer, mais il était déjà activé par défaut)

Quant à savoir pourquoi il n'y a pas de suppression en cascade explicite dans l'autre cas, je ne suis pas sûr, mais je pense que cela pourrait également être par défaut dans SQL, donc WillCascadeOnDelete (true) ne le fait tout simplement pas changer quoi que ce soit de n'importe quel côté. Cependant, vous pourriez obtenir des résultats différents si vous essayez WillCascadeOnDelete (false) qui devrait remplacer le comportement par défaut basé sur la documentation.


5 commentaires

Je suppose que vous voulez dire que CriteriaId est nullable? Parce que QuestionId ne l'est pas. J'ai configuré le CriteriaId pour forcer la suppression en cascade, ce qui est très bien. Mais comme Answers, Attributes ne semble pas avoir la suppression en cascade activée même lorsque vous définissez WillCascadeOnDelete sur true. De plus, AttributeId / AnswerId est obligatoire, donc la suppression en cascade doit être activée, mais ce n'est pas le cas. J'ai mis à jour ma question pour afficher mon DbContext dans son intégralité


@ r3plica désolé, je voulais dire CategoryId puisque le premier exemple concerne la relation Question -to- Category . J'ai modifié ma réponse en conséquence.


Coolio, ça tient toujours. Criteria a la suppression en cascade qui semble avoir été extraite de WillCascadeOnDelete . Je n'arrive toujours pas à comprendre pourquoi les autres ne le sont pas ...


@ r3plica ce que je voulais dire, c'est que cela pourrait être le comportement par défaut pour EntityFramework et SQL Server, donc il n'ajoute pas l'instruction explicite. Cependant, je ne suis pas sûr de cela, des expériences seraient nécessaires. Avez-vous essayé WillCascadeOnDelete (false) juste pour voir si cela change le comportement par défaut possible?


Cela ne semble pas être le comportement par défaut, mais j'ai trouvé une solution



0
votes

Donc, cela me dérangeait; J'ai décidé de modifier mon DbContext . J'ai d'abord désactivé toutes les suppressions en cascade, puis j'ai mis à jour la base de données comme ceci:

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

Lorsque cela s'est exécuté, il a mis à jour correctement les clés étrangères. Je pouvais voir ceci:

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

Ce que je pouvais voir était correct. Ensuite, j'ai créé une nouvelle migration après avoir modifié mon DbContext retour:

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

Ce qui a généré ceci:

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

Comme vous pouvez le voir, chaque clé étrangère a maintenant:

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

Il s'agit donc explicitement de paramétrer l'option cascadeDelete qui n'a jamais été présente.

Alors, que dois-je conclure? Il semble que lors de la configuration initiale d'un code de base de données, vous ne pouvez pas et ne devez pas compter sur EntityFramework pour créer une suppression en cascade. Si vous le souhaitez, vous devez le spécifier lors de la création. Cela devrait éviter que mon problème ne vous arrive. Mais, si c'est le cas, désactivez-le et réactivez-le lors de la prochaine migration et cela résoudra votre problème.


0 commentaires