c# - Entity Framework Code First: due chiavi esterne dalla stessa tabella




entity-framework orm (4)

È anche possibile specificare l'attributo ForeignKey() sulla proprietà di navigazione:

[ForeignKey("HomeTeamID")]
public virtual Team HomeTeam { get; set; }
[ForeignKey("GuestTeamID")]
public virtual Team GuestTeam { get; set; }

In questo modo non è necessario aggiungere alcun codice al metodo OnModelCreate

Ho appena iniziato a utilizzare prima il codice EF, quindi sono un principiante assoluto in questo argomento.

Volevo creare relazioni tra team e partite: 1 partita = 2 squadre (casa, ospite) e risultato. Ho pensato che è facile creare tale modello, quindi ho iniziato a scrivere:

public class Team
{
    [Key]
    public int TeamId { get; set;} 
    public string Name { get; set; }

    public virtual ICollection<Match> Matches { get; set; }
}


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

    [ForeignKey("HomeTeam"), Column(Order = 0)]
    public int HomeTeamId { get; set; }
    [ForeignKey("GuestTeam"), Column(Order = 1)]
    public int GuestTeamId { get; set; }

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

    public virtual Team HomeTeam { get; set; }
    public virtual Team GuestTeam { get; set; }
}

E ottengo un'eccezione:

La relazione referenziale genererà un riferimento ciclico che non è consentito. [Nome vincolo = Match_GuestTeam]

Come posso creare tale modello, con 2 chiavi esterne allo stesso tavolo? TIA.


Prova questo:

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; }
}

public class Match
{
    public int MatchId { get; set; }

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

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

    public virtual Team HomeTeam { get; set; }
    public virtual Team GuestTeam { get; set; }
}


public class Context : DbContext
{
    ...

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Match>()
                    .HasRequired(m => m.HomeTeam)
                    .WithMany(t => t.HomeMatches)
                    .HasForeignKey(m => m.HomeTeamId)
                    .WillCascadeOnDelete(false);

        modelBuilder.Entity<Match>()
                    .HasRequired(m => m.GuestTeam)
                    .WithMany(t => t.AwayMatches)
                    .HasForeignKey(m => m.GuestTeamId)
                    .WillCascadeOnDelete(false);
    }
}

Le chiavi primarie sono mappate per convenzione predefinita. La squadra deve avere due raccolte di partite. Non è possibile avere un'unica raccolta referenziata da due FK. La corrispondenza viene mappata senza eliminazione a cascata perché non funziona in questi riferimenti self-to-molti.


Questo perché le eliminazioni in cascata sono abilitate per impostazione predefinita. Il problema è che quando chiamate un'eliminazione sull'entità, cancellerà anche ciascuna delle entità referenziate con la chiave f. Non dovresti rendere nullable i valori "richiesti" per risolvere questo problema. Un'opzione migliore sarebbe quella di rimuovere la convenzione di eliminazione Cascade del codice EF First:

modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>(); 

Probabilmente è più sicuro indicare esplicitamente quando eseguire una cancellazione a cascata per ciascuno dei bambini durante l'associazione / configurazione. l'entità.


So che è un post di diversi anni e potresti risolvere il tuo problema con la soluzione di cui sopra. Tuttavia, voglio solo suggerire di usare InverseProperty per qualcuno che ha ancora bisogno. Almeno non è necessario modificare nulla in OnModelCreating.

Il codice sottostante non è testato.

public class Team
{
    [Key]
    public int TeamId { get; set;} 
    public string Name { get; set; }

    [InverseProperty("HomeTeam")]
    public virtual ICollection<Match> HomeMatches { get; set; }

    [InverseProperty("GuestTeam")]
    public virtual ICollection<Match> GuestMatches { get; set; }
}


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

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

    public virtual Team HomeTeam { get; set; }
    public virtual Team GuestTeam { get; set; }
}

Puoi leggere ulteriori informazioni su InverseProperty su MSDN: https://msdn.microsoft.com/en-us/data/jj591583?f=255&MSPPError=-2147217396#Relationships







entity-framework-4.1