web-dev-qa-db-fra.com

Entity Framework Core: Comment résoudre le problème L'introduction d'une contrainte FOREIGN KEY peut provoquer des cycles ou plusieurs chemins en cascade

J'utilise Entity Framework Core avec l'approche Code First mais reçois l'erreur suivante lors de la mise à jour de la base de données:

L'introduction de la contrainte FOREIGN KEY 'FK_AnEventUsers_Users_UserId' sur la table 'AnEventUsers' peut provoquer des cycles ou plusieurs chemins en cascade. Indiquez ON DELETE NO ACTION ou ON UPDATE NO ACTION ou modifiez d'autres contraintes FOREIGN KEY. Impossible de créer une contrainte ou un index. Voir les erreurs précédentes. 

Mes entités sont celles-ci: 

public class AnEvent
{
    public int AnEventId { get; set; }
    public DateTime Time { get; set; }
    public Gender Gender { get; set; }
    public int Duration { get; set; }
    public Category Category { get; set; }
    public int MinParticipants { get; set; }
    public int MaxParticipants { get; set; }
    public string Description { get; set; }
    public Status EventStatus { get; set; }
    public int MinAge { get; set; }
    public int MaxAge { get; set; }
    public double Longitude { get; set; }
    public double Latitude { get; set; }

    public ICollection<AnEventUser> AnEventUsers { get; set; }

    public int UserId { get; set; }
    public User User { get; set; }
}


public class User
{
    public int UserId { get; set; }
    public int Age { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Gender Gender { get; set; }
    public double Rating { get; set; }

    public ICollection<AnEventUser> AnEventUsers { get; set; }
}

public class AnEventUser
{
    public int AnEventId { get; set; }
    public AnEvent AnEvent { get; set; }

    public int UserId { get; set; }
    public User User { get; set; }

}

public class ApplicationDbContext:DbContext
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options):base(options)
    { }


    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<AnEventUser>()
            .HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);


        modelBuilder.Entity<AnEventUser>()
            .HasKey(t => new { t.AnEventId, t.UserId });

        modelBuilder.Entity<AnEventUser>()
            .HasOne(pt => pt.AnEvent)
            .WithMany(p => p.AnEventUsers)
            .HasForeignKey(pt => pt.AnEventId);

        modelBuilder.Entity<AnEventUser>()
            .HasOne(eu => eu.User)
            .WithMany(e => e.AnEventUsers)
            .HasForeignKey(eu => eu.UserId);

    }

    public DbSet<AnEvent> Events { get; set; }
    public DbSet<User> Users { get; set; }
    public DbSet<AnEventUser> AnEventUsers { get; set; }
}

Le problème que je pensais était que si nous supprimons un utilisateur, la référence à AnEvent sera supprimée, ainsi que la référence à AnEventUser, car il y a une référence à AnEventUser à partir de AnEvent et nous obtenons des chemins en cascade. Mais je supprime la cascade de suppression de User à AnEventUser avec:

 modelBuilder.Entity<AnEventUser>()
        .HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);

Mais l'erreur ne se résout pas, est-ce que quelqu'un voit ce qui ne va pas? Merci!

7
Mu2tini

Dans votre exemple de code dans OnModelCreating, vous avez déclaré modelBuilder.Entity<AnEventUser>().HasOne(e => e.User)... deux fois: au début de la méthode et à la fin.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<AnEventUser>()       // THIS IS FIRST
        .HasOne(u => u.User).WithMany(u => u.AnEventUsers).IsRequired().OnDelete(DeleteBehavior.Restrict);


    modelBuilder.Entity<AnEventUser>()
        .HasKey(t => new { t.AnEventId, t.UserId });

    modelBuilder.Entity<AnEventUser>()
        .HasOne(pt => pt.AnEvent)
        .WithMany(p => p.AnEventUsers)
        .HasForeignKey(pt => pt.AnEventId);

    modelBuilder.Entity<AnEventUser>()       // THIS IS SECOND.
        .HasOne(eu => eu.User)               // THIS LINES
        .WithMany(e => e.AnEventUsers)       //   SHOULD BE
        .HasForeignKey(eu => eu.UserId);     //   REMOVED

}

Le deuxième appel annule en premier. Enlevez-le.

8
Dmitry

Voici ce que j'ai fait de la réponse de Dmitry, 

et cela a fonctionné pour moi.

Classe:

public class EnviornmentControls
{
    public int Id { get; set; }
    ...

    public virtual Environment Environment { get; set; }
}

Et c'est la cartographie 

public EnviornmentControlsMap(EntityTypeBuilder<EnviornmentControls> entity)
{
        entity.HasKey(m => m.Id);           

        entity.HasOne(m => m.Environment)
            .WithMany(m => m.EnviornmentControls)
            .HasForeignKey(m => m.EnvironmentID)
            .OnDelete(DeleteBehavior.Restrict); // added OnDelete to avoid sercular reference 
}
2
Bharat

Ces solutions n'ont pas fonctionné pour mon cas, mais j'ai trouvé un moyen. Je ne sais pas encore s'il est sûr mais il y a juste quelque chose qui se passe avec la suppression. J'ai donc modifié le fichier de migration généré au lieu de remplacer le fichier.

onDelete: ReferentialAction.Cascade

La raison pour laquelle j'ai fait cela parce que tous les dépassements mentionnés ci-dessus ne fonctionne pas pour moi, j'ai donc supprimé manuellement le code qui concerne la suppression en cascade.

Il suffit de vérifier quelle relation spécifique est mentionnée à l'erreur pour pouvoir y aller directement.

J'espère que cela pourra aider certaines personnes qui ont le même problème que le mien.

0
Siege21x