Entity framework 7 in ASP.NET MVC6 più chiavi esterne per la stessa tabella

asp.net-mvc entity-framework entity-framework-core

Domanda

Ciao ho lo stesso problema che un vecchio post è qui, la soluzione offerta non funziona per me in MVC 6 con EF7 è semplice

public class Match
{
    [Key]
    public int MatchId { get; set; }

    public DateTime playday { get; set; }
    public float HomePoints { get; set; }
    public float GuestPoints { get; set; }

    public int HomeTeamId { get; set; }
    public int GuestTeamId { get; set; }

    [ForeignKey("HomeTeamId")]
    [InverseProperty("HomeMatches")]
    public virtual Team HomeTeam { get; set; }

    [ForeignKey("GuestTeamId")]
    [InverseProperty("AwayMatches")]
    public virtual Team GuestTeam { get; set; }

}

public class Team
{
    public int TeamId { get; set; }
    public String name { get; set; }

    public virtual ICollection<Match> HomeMatches { get; set; }
    public virtual ICollection<Match> AwayMatches { get; set; }
}

questo è il modo migliore che ho trovato, perché posso aggiungere una nuova migrazione e tutto è ok, ma quando aggiorno il database ottengo un errore come questo

L'introduzione del vincolo FOREIGN KEY "FK_Match_Team_HomeTeamId" nella tabella "Corrispondenza" può causare cicli o più percorsi a cascata. Specificare ON DELETE NO ACTION o ON UPDATE NO ACTION o modificare altri vincoli FOREIGN KEY. Impossibile creare vincoli o indici. Vedi errori precedenti.

Risposta accettata

Ho analizzato il problema in dettaglio durante la preparazione della risposta e posso suggerirvi due soluzioni del problema.

Il problema esiste a causa di due proprietà nella classe Match

public int HomeTeamId { get; set; }
public int GuestTeamId { get; set; }

e le chiavi HomeTeamId e GuestTeamId che verranno generate. EF7 genera le chiavi esterne con ON DELETE CASCADE , che non può essere utilizzato per più come una chiave esterna. L'attuale implementazione di Entity Framework (RC1) non ha attributo di annotazione, che è possibile utilizzare per modificare il comportamento.

La prima soluzione del problema sarebbe quella di utilizzare proprietà nullable come

public int? HomeTeamId { get; set; }
public int? GuestTeamId { get; set; }

o

public int HomeTeamId { get; set; }
public int? GuestTeamId { get; set; }

La massima proprietà deve essere non annullabile. Di conseguenza il problema verrà risolto, ma si avrà un piccolo svantaggio, che potrebbe non essere importante per alcuni scenari. Il campo nella tabella del database per la proprietà nullable non avrà alcuna proprietà NOT NULL nella definizione della colonna.

Se è necessario mantenere entrambi non HomeTeamId come HomeTeamId e GuestTeamId , è possibile risolvere il problema modificando la classe di contesto (ereditata da DbContext), in cui vengono utilizzate le classi Match e Team .

Di seguito è già presente una riga definita dalla classe di contesto

public class MyDBContext : DbContext
{
    DbSet<Team> Teams { get; set; }
    DbSet<Match> Matches { get; set; }
}

Per risolvere il problema descritto è possibile aggiungere OnModelCreating protetto nella classe che imposta esplicitamente

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

        modelbuilder.Entity(typeof (Match))
            .HasOne(typeof (Team), "GuestTeam")
            .WithMany()
            .HasForeignKey("GuestTeamId")
            .OnDelete(DeleteBehavior.Restrict); // no ON DELETE

        modelbuilder.Entity(typeof (Match))
            .HasOne(typeof (Team), "HomeTeam")
            .WithMany()
            .HasForeignKey("GuestTeamId")
            .OnDelete(DeleteBehavior.Cascade); // set ON DELETE CASCADE
    }

    DbSet<Team> Teams { get; set; }
    DbSet<Match> Matches { get; set; }
}

È possibile utilizzare causa causa DeleteBehavior.Restrict su entrambe le chiavi esterne (anziché l'utilizzo di DeleteBehavior.Cascade su uno). È importante notare che l'ultimo approccio consente di mantenere sia HomeTeamId che GuestTeamId , come i campi corrispondenti nel database, come non annullabili.

Vedere la documentazione per ulteriori informazioni.


Risposta popolare

Se si preferisce, è possibile creare manualmente sul database questo FK con eliminazione a cascata e verificare il motivo per cui si ha questo ciclo circolare a cascata. Per capire che abbiamo bisogno delle altre tabelle o della struttura del database coinvolta. Controlla il tuo database (con uno schema per esempio), disegna le tabelle connesse, i tuoi FK e per ogni studio l'operazione che hai pianificato (eliminazione a cascata, nessuna azione, ...) e la direzione di essi. Riempi il ciclo di ricerca quando cerchi di inserire quell'FK in errore.

La fase successiva è capire se lo vuoi o no, è un progetto di database indesiderato? O semplicemente non hai bisogno di questa azione FK? In questo caso puoi sopprimerlo a vari livelli: su modello, su impostazioni, ... vedi l'altro post o la guida EF per questo.



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché