web-dev-qa-db-fra.com

Spécifier ON DELETE NO ACTION dans Entity Framework 7?

Dans Entity Framework 7 lorsque j'essaie d'appliquer une migration, j'obtiens l'erreur

L'introduction de la contrainte FOREIGN KEY 'FK_ChangeOrder_User_CreatedByID' sur la table 'ChangeOrder' peut provoquer des cycles ou plusieurs chemins de cascade. Spécifiez ON DELETE NO ACTION ou ON UPDATE NO ACTION, ou modifiez d'autres contraintes FOREIGN KEY.
Impossible de créer une contrainte. Voir les erreurs précédentes.

Je sais que dans les anciennes versions d'Entity Framework, vous géreriez cela en ajoutant

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

au DbContext mais dans EF7 modelBuilder ne semble pas avoir un .Conventions et Google ne renvoie que les anciens EF 4 à EF 6.

Comment spécifier le ON DELETE NO ACTION contrainte dans Entity Framework 7?

Edit: La réponse fournie par Oleg le fera apparemment par clé étrangère, mais je voudrais le faire globalement car il sera beaucoup plus facile d'utiliser une ligne de code pour le déclarer globalement, puis de le spécifier pour chaque code des centaines de relations que je finirai par avoir.

Edit 2: Code pour Oleg

public class ChangeOrder
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public int ID { get; set; }

    public Int16? ApprovedByID { get; set; }
    public Byte ApprovalStatusID { get; set; }
    public Int16 AssignedToID { get; set; }
    public Int16 CreatedByID { get; set; }
    public Byte CurrentStatusID { get; set; }
    public DateTime? DateApproved { get; set; }
    public DateTime? EndDate { get; set; }
    public Byte ImpactID { get; set; }
    public Byte PriorityID { get; set; }
    public DateTime? StartDate { get; set; }
    public Byte TypeID { get; set; }

    [Required]
    public string Name { get; set; }

    [Required]
    public string ReasonForChange { get; set; }

    [ForeignKey("ApprovedByID")]
    public User ApprovedBy { get; set; }

    [ForeignKey("ApprovalStatusID")]
    public ChangeApprovalStatus ApprovalStatus { get; set; }

    [ForeignKey("AssignedToID")]
    public User AssignedTo { get; set; }

    [ForeignKey("CreatedByID")]
    public User CreatedBy { get; set; }

    [ForeignKey("ImpactID")]
    public ChangeImpact Impact { get; set; }

    [ForeignKey("PriorityID")]
    public ChangePriority Priority { get; set; }

    [ForeignKey("TypeID")]
    public ChangeType ChangeType { get; set; }

    [ForeignKey("CurrentStatusID")]
    public ChangeStatus CurrentStatus { get; set; }
}
public class JobSightDBContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelbuilder)
    {
        base.OnModelCreating(modelbuilder);
    }

    DbSet<ChangeApprovalStatus> ChangeApprovalStatus { get; set; }
    DbSet<ChangeImpact> ChangeImapct { get; set; }
    DbSet<ChangeOrder> ChangeOrders { get; set; }
    DbSet<ChangePriority> ChangePriorities { get; set; }
    DbSet<ChangeStatus> ChangeStatus { get; set; }
    DbSet<ChangeType> ChangeTypes { get; set; }
    DbSet<User> Users { get; set; }
}
29
Matthew Verstraete

Après avoir creusé sur GitHub et travaillé avec un gars très patient de MS là-bas, la solution actuelle consiste à l'ajouter au DbContext

protected override void OnModelCreating(ModelBuilder modelbuilder)
{
    foreach (var relationship in modelbuilder.Model.GetEntityTypes().SelectMany(e => e.GetForeignKeys()))
    {
        relationship.DeleteBehavior = DeleteBehavior.Restrict;
    }

    base.OnModelCreating(modelbuilder);
}
53
Matthew Verstraete

La construction

modelBuilder.Entity("myNamespace.Models.ChangeOrder", b =>
    {
        b.HasOne("myNamespace.Models.User")
            .WithMany()
            .HasForeignKey("CreatedByID")
            .OnDelete(DeleteBehavior.Cascade);
    });

will signifie créer FK_ChangeOrder_User_CreatedByID avec REFERENCES [dbo].[User] ([CreatedByID]) ON DELETE CASCADE. Il doit exister dans protected override void BuildModel(ModelBuilder modelBuilder) de YourContextModelSnapshot.cs Créé lors de la migration. Je ne suis pas sûr d'avoir bien compris votre question, mais je pense que vous devriez soit ajouter une telle construction à XXXModelSnapshot.cs Soit supprimer une construction inutile, qui existe déjà ici.

MISE À JOUR: Je vois que vous avez le problème dans le modèle. Vous avez les propriétés suivantes dans

public Int16? ApprovedByID { get; set; }
public Int16 AssignedToID { get; set; }
public Int16 CreatedByID { get; set; }

// navigation properties

[ForeignKey("ApprovedByID")]
public User ApprovedBy { get; set; }

[ForeignKey("AssignedToID")]
public User AssignedTo { get; set; }

[ForeignKey("CreatedByID")]
public User CreatedBy { get; set; }

Par défaut, la migration essaie de définir DeleteBehavior.Cascade Sur toutes les propriétés.

Vous pouvez remplacer le comportement en modifiant OnModelCreating, qui définit le comportement DeleteBehavior.Restrict Pour toutes les clés ou pour définir sur une seule clé le comportement DeleteBehavior.Cascade Ou DeleteBehavior.SetNull . Par exemple, le code ci-dessous utilise DeleteBehavior.Cascade Sur CreatedByID (ce qui crée ON DELETE CASCADE Sur les clés étrangères) et DeleteBehavior.Restrict Sur d'autres clés étrangères (non ON DELETE Sur les clés étrangères):

public class JobSightDBContext : DbContext
{
    protected override void OnModelCreating(ModelBuilder modelbuilder)
    {
        base.OnModelCreating(modelbuilder);

        modelbuilder.Entity(typeof (ChangeOrder))
            .HasOne(typeof (User), "ApprovedBy")
            .WithMany()
            .HasForeignKey("ApprovedByID")
            .OnDelete(DeleteBehavior.Restrict); // no ON DELETE
        modelbuilder.Entity(typeof (ChangeOrder))
            .HasOne(typeof (User), "AssignedTo")
            .WithMany()
            .HasForeignKey("AssignedToID")
            .OnDelete(DeleteBehavior.Restrict); // no ON DELETE
        modelbuilder.Entity(typeof (ChangeOrder))
            .HasOne(typeof (User), "CreatedBy")
            .WithMany()
            .HasForeignKey("CreatedByID")
            .OnDelete(DeleteBehavior.Cascade); // set ON DELETE CASCADE
    }

    DbSet<ChangeApprovalStatus> ChangeApprovalStatus { get; set; }
    DbSet<ChangeImpact> ChangeImapct { get; set; }
    DbSet<ChangeOrder> ChangeOrders { get; set; }
    DbSet<ChangePriority> ChangePriorities { get; set; }
    DbSet<ChangeStatus> ChangeStatus { get; set; }
    DbSet<ChangeType> ChangeTypes { get; set; }
    DbSet<User> Users { get; set; }
}
15
Oleg