.net - net - entity framework database first




L'introduction de la contrainte FOREIGN KEY peut provoquer des cycles ou des chemins en cascade multiples-pourquoi? (9)

Je me bats avec ça depuis un moment et je n'arrive pas à comprendre ce qui se passe. J'ai une entité de carte qui contient des côtés (habituellement 2) - et les cartes et les côtés ont une scène. J'utilise les migrations EF Codefirst et les migrations échouent avec cette erreur:

L'introduction de la contrainte FOREIGN KEY 'FK_dbo.Sides_dbo.Cards_CardId' sur la table 'Sides' peut provoquer des cycles ou plusieurs chemins en cascade. Spécifiez ON DELETE NO ACTION ou ON UPDATE NO ACTION ou modifiez d'autres contraintes FOREIGN KEY.

Voici mon entité Card :

public class Card
{
    public Card()
    {
        Sides = new Collection<Side>();
        Stage = Stage.ONE;
    }

    [Key]
    [Required]
    public virtual int CardId { get; set; }

    [Required]
    public virtual Stage Stage { get; set; }

    [Required]
    [ForeignKey("CardId")]
    public virtual ICollection<Side> Sides { get; set; }
}

Voici mon entité Side :

public class Side
{
    public Side()
    {
        Stage = Stage.ONE;
    }

    [Key]
    [Required]     
    public virtual int SideId { get; set; } 

    [Required]
    public virtual Stage Stage { get; set; }

    [Required]
    public int CardId { get; set; }

    [ForeignKey("CardId")]
    public virtual Card Card { get; set; }

}

Et voici mon entité Stage :

public class Stage
{
    // Zero
    public static readonly Stage ONE = new Stage(new TimeSpan(0, 0, 0), "ONE");
    // Ten seconds
    public static readonly Stage TWO = new Stage(new TimeSpan(0, 0, 10), "TWO");

    public static IEnumerable<Stage> Values
    {
        get
        {
            yield return ONE;
            yield return TWO;
        }

    }

    public int StageId { get; set; }
    private readonly TimeSpan span;
    public string Title { get; set; }

    Stage(TimeSpan span, string title)
    {
        this.span = span;
        this.Title = title;
    }

    public TimeSpan Span { get { return span; } }
}

Ce qui est étrange, c'est que si j'ajoute ce qui suit à ma classe Stage:

    public int? SideId { get; set; }
    [ForeignKey("SideId")]
    public virtual Side Side { get; set; }

La migration s'exécute avec succès. Si j'ouvre SSMS et regarde les tables, je peux voir que Stage_StageId a été ajouté aux Cards (comme attendu / désiré), cependant Sides ne contient aucune référence à Stage (pas attendu).

Si je puis ajouter

    [Required]
    [ForeignKey("StageId")]
    public virtual Stage Stage { get; set; }
    public int StageId { get; set; }

Pour ma classe Side, je vois la colonne StageId ajoutée à ma table d' Side .

Cela fonctionne, mais maintenant, tout au long de mon application, toute référence à Stage contient un SideId , qui est dans certains cas totalement hors de propos. Je voudrais juste donner à mes entités Card et Side une propriété Stage basée sur la classe Stage ci-dessus sans polluer la classe stage avec des propriétés de référence si possible ... qu'est-ce que je fais de mal?


Aucune des solutions susmentionnées n'a fonctionné pour moi. Ce que je devais faire était d'utiliser un int null (int?) Sur la clé étrangère qui n'était pas nécessaire (ou pas une clé de colonne null) et ensuite supprimer certaines de mes migrations.

Commencez par supprimer les migrations, puis essayez l'intensible null.

Le problème était à la fois une modification et une conception de modèle. Aucun changement de code n'était nécessaire.


Cela semble étrange et je ne sais pas pourquoi, mais dans mon cas, cela arrivait parce que mon ConnectionString utilisait "." dans l'attribut "source de données". Une fois que je l'ai changé à "localhost" il a travaillé comme un charme. Aucun autre changement n'était nécessaire.


Dans .NET Core, j'ai joué avec toutes les réponses supérieures - mais sans succès. J'ai fait beaucoup de changements dans la structure DB et à chaque fois j'ai ajouté une nouvelle migration en essayant de update-database à update-database , mais j'ai reçu la même erreur.

Ensuite, j'ai commencé à remove-migration un par un jusqu'à ce que Package Manager Console me lève l'exception:

La migration '20170827183131 _ ***' a déjà été appliquée à la base de données

Après cela, j'ai ajouté une nouvelle migration ( add-migration ) et update-database avec succès

Donc, ma suggestion serait: effacer toutes vos migrations temp, jusqu'à votre état de DB actuel.


J'ai eu ce problème aussi, je l'ai résolu instantanément avec cette réponse d'un fil similaire

Dans mon cas, je ne voulais pas supprimer l'enregistrement dépendant à la suppression de la clé. Si c'est le cas dans votre situation, changez simplement la valeur booléenne dans la migration en false:

AddForeignKey("dbo.Stories", "StatusId", "dbo.Status", "StatusID", cascadeDelete: false);

Les chances sont, si vous créez des relations qui lancent cette erreur du compilateur mais que vous voulez maintenir la suppression en cascade; vous avez un problème avec vos relations.


J'avais une table qui avait une relation circulaire avec les autres et je recevais la même erreur. Il s'avère qu'il s'agit de la clé étrangère qui n'était pas nulle. Si la clé n'est pas nullable, l'objet associé doit être supprimé et les relations circulaires ne le permettent pas. Utilisez donc une clé étrangère nullable.

[ForeignKey("StageId")]
public virtual Stage Stage { get; set; }
public int? StageId { get; set; }

Je recevais cette erreur pour beaucoup d'entités lorsque je passais d'un modèle EF7 à une version EF6. Je ne voulais pas devoir passer par chaque entité une à la fois, alors j'ai utilisé:

builder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
builder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

Les réponses existantes sont géniales Je voulais juste ajouter que j'ai rencontré cette erreur pour une raison différente. Je voulais créer une migration EF initiale sur une base de données existante, mais je n'ai pas utilisé l'indicateur -IgnoreChanges et appliqué la commande Update-Database sur une base de données vide (également sur les échecs existants).

Au lieu de cela, j'ai dû exécuter cette commande lorsque la structure db actuelle est la suivante:

Add-Migration Initial -IgnoreChanges

Il y a probablement un vrai problème dans la structure db mais sauver le monde une étape à la fois ...


Quelqu'un se demande comment le faire dans le noyau EF:

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

Stage donné que Stage est requis pour toutes les relations un-à-plusieurs dans lesquelles Stage est impliqué, la suppression en cascade est activée par défaut. Cela signifie que si vous supprimez une entité Stage

  • la suppression sera directement en cascade vers Side
  • l'effacement se répercutera directement sur la Card et parce que la Card et le Side ont une relation un-à-plusieurs requise avec la suppression en cascade activée par défaut, elle sera alors en cascade de la Card vers l' Side

Vous disposez donc de deux chemins de suppression en cascade de l' Stage à l' Side , ce qui provoque l'exception.

Vous devez rendre la Stage facultative dans au moins une des entités (c'est-à-dire supprimer l'attribut [Required] des propriétés de la Stage ) ou désactiver la suppression en cascade avec l'API Fluent (impossible avec les annotations de données):

modelBuilder.Entity<Card>()
    .HasRequired(c => c.Stage)
    .WithMany()
    .WillCascadeOnDelete(false);

modelBuilder.Entity<Side>()
    .HasRequired(s => s.Stage)
    .WithMany()
    .WillCascadeOnDelete(false);




ef-code-first