L’introduzione del vincolo FOREIGN KEY può causare cicli o più percorsi a cascata: perché?

Sono stato a lottare con questo per un po ‘e non riesco a capire cosa sta succedendo. Ho un’entity framework Card che contiene Lati (solitamente 2) – e entrambe le Carte e i Lati hanno uno Stage. Sto usando EF Codefirst migrazioni e le migrazioni falliscono con questo errore:

L’introduzione del vincolo FOREIGN KEY “FK_dbo.Sides_dbo.Cards_CardId” sulla tabella “Lati” può causare cicli o più percorsi a cascata. Specificare ON DELETE NO ACTION o ON UPDATE NO ACTION o modificare altri vincoli FOREIGN KEY.

Ecco la mia quadro Card :

public class Card { public Card() { Sides = new Collection(); Stage = Stage.ONE; } [Key] [Required] public virtual int CardId { get; set; } [Required] public virtual Stage Stage { get; set; } [Required] [ForeignKey("CardId")] public virtual ICollection Sides { get; set; } } 

Ecco la mia quadro 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; } } 

Ed ecco la mia quadro 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 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; } } } 

Ciò che è strano è che se aggiungo quanto segue alla mia lezione di Stage:

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

La migrazione viene eseguita correttamente. Se apro SSMS e guardo le tabelle, posso vedere che Stage_StageId è stato aggiunto a Cards (come previsto / desiderato), tuttavia Sides non contiene riferimenti a Stage (non previsti).

Se poi aggiungo

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

Nella mia class Side, vedo la colonna StageId aggiunta al mio Side table.

SideId , ma ora in tutta la mia applicazione, ogni riferimento a Stage contiene un SideId , che in alcuni casi è del tutto irrilevante. Vorrei semplicemente dare alle mie quadro Card e Side una proprietà Stage basata sulla class Stage precedente senza inquinare la class stage con le proprietà di riferimento, se ansible … cosa sto facendo male?

Poiché Stage è richiesto , tutte le relazioni uno-a-molti in cui è coinvolto Stage avranno l’eliminazione a catena abilitata per impostazione predefinita. Significa, se elimini un’entity framework Stage

  • l’eliminazione si sovrapporrà direttamente a Side
  • l’eliminazione si sovrapporrà direttamente alla Card e poiché la Card e il Side hanno una relazione uno-a-molti richiesta con l’eliminazione a cascata abilitata di default, questa verrà quindi convertita in cascata da Card a Card

Quindi, hai due percorsi di eliminazione a cascata da Stage a Side – che causa l’eccezione.

È necessario rendere lo Stage facoltativo in almeno una delle quadro (ovvero rimuovere l’attributo [Required] dalle proprietà dello Stage ) o disabilitare l’eliminazione a catena con l’API Fluent (non ansible con le annotazioni di dati):

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

Avevo un tavolo che aveva una relazione circolare con gli altri e stavo ottenendo lo stesso errore. Si scopre che si tratta della chiave esterna che non era annullabile. Se la chiave non è nullable, l’object correlato deve essere eliminato e le relazioni circolari non lo consentono. Quindi usa la chiave straniera nullable.

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

Stavo ricevendo questo errore per molte quadro durante la migrazione da un modello EF7 a una versione EF6. Non volevo passare attraverso ciascuna quadro una alla volta, quindi ho usato:

 builder.Conventions.Remove(); builder.Conventions.Remove(); 

Qualcuno si chiede come farlo nel core 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..... 

È ansible impostare cascadeDelete su false o true (nel metodo di migrazione Up ()). Dipende dal vostro requisito

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

Ho avuto anche questo problema, l’ho risolto immediatamente con questa risposta da un thread simile

Nel mio caso, non volevo eliminare il record dipendente alla cancellazione della chiave. Se questo è il caso nella tua situazione, basta semplicemente cambiare il valore booleano nella migrazione in falso:

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

Le probabilità sono, se si creano relazioni che generano questo errore del compilatore ma si desidera mantenere l’eliminazione a cascata; hai un problema con le tue relazioni.

Sembra strano e non so perché, ma nel mio caso ciò stava accadendo perché il mio ConnectionString stava usando “.” nell’attributo “origine dati”. Una volta cambiato in “localhost” ha funzionato come un fascino. Non è stato necessario nessun altro cambiamento

In .NET Core ho cambiato l’opzione onDelete in ReferencialAction.NoAction

  constraints: table => { table.PrimaryKey("PK_Schedule", x => x.Id); table.ForeignKey( name: "FK_Schedule_Teams_HomeId", column: x => x.HomeId, principalTable: "Teams", principalColumn: "Id", onDelete: ReferentialAction.NoAction); table.ForeignKey( name: "FK_Schedule_Teams_VisitorId", column: x => x.VisitorId, principalTable: "Teams", principalColumn: "Id", onDelete: ReferentialAction.NoAction); }); 

Le risposte esistenti sono fantastiche. Volevo solo aggiungere che ho riscontrato questo errore a causa di un motivo diverso. Volevo creare una migrazione EF iniziale su un DB esistente ma non ho usato il flag -IgnoreChanges e applicato il comando Update-Database su un database vuoto (anche in caso di errori esistenti).

Invece ho dovuto eseguire questo comando quando la struttura db corrente è quella corrente:

 Add-Migration Initial -IgnoreChanges 

È probabile che ci sia un vero problema nella struttura del database, ma salvare il mondo un passo alla volta …

Ho risolto questo. Quando aggiungi la migrazione, nel metodo Up () ci sarà una riga come questa:

.ForeignKey (“dbo.Members”, t => t.MemberId, cascadeDelete: True)

Se si elimina il cascadeDelete dalla fine, funzionerà.

Solo per scopi di documentazione, per qualcuno che viene in futuro, questa cosa può essere risolta in modo semplice come questo, e con questo metodo, potresti fare un metodo che è disabilitato una volta, e potresti accedere normalmente al tuo metodo

Aggiungi questo metodo alla class del database di contesto:

 protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Conventions.Remove(); } 

In .NET Core ho giocato con tutte le risposte migliori, ma senza alcun successo. Ho apportato molte modifiche alla struttura del database e ogni volta ho aggiunto una nuova migrazione per tentare di update-database , ma ho ricevuto lo stesso errore.

Quindi ho iniziato a remove-migration una alla volta finché Package Manager Console non mi ha lanciato un’eccezione:

La migrazione ‘20170827183131 _ ***’ è già stata applicata al database

Successivamente, ho aggiunto la nuova migrazione ( add-migration ) e il update-database correttamente

Quindi il mio suggerimento sarebbe: cancellare tutte le migrazioni temporanee, fino allo stato attuale del DB.

Nessuna delle soluzioni di cui sopra ha funzionato per me. Quello che dovevo fare era usare un nullable int (int?) Sulla chiave esterna che non era richiesta (o non una chiave di colonna non nullo) e quindi cancellare alcune delle mie migrazioni.

Inizia eliminando le migrazioni, quindi prova il nullable int.

Il problema era sia una modifica che una progettazione del modello. Non è stato necessario modificare il codice.