Primero, el código del Entity Framework: dos claves externas de la misma tabla

Acabo de empezar a usar el código EF primero, así que soy un principiante total en este tema.

Quería crear relaciones entre equipos y partidos: 1 partido = 2 equipos (hogar, invitado) y resultado. Pensé que es fácil crear dicho modelo, así que comencé a codificar:

public class Team { [Key] public int TeamId { get; set;} public string Name { get; set; } public virtual ICollection 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; } } 

Y obtengo una excepción:

La relación referencial dará como resultado una referencia cíclica que no está permitida. [Nombre de restricción = Match_GuestTeam]

¿Cómo puedo crear dicho modelo, con 2 claves externas en la misma tabla? TIA.

Prueba esto:

 public class Team { public int TeamId { get; set;} public string Name { get; set; } public virtual ICollection HomeMatches { get; set; } public virtual ICollection 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() .HasRequired(m => m.HomeTeam) .WithMany(t => t.HomeMatches) .HasForeignKey(m => m.HomeTeamId) .WillCascadeOnDelete(false); modelBuilder.Entity() .HasRequired(m => m.GuestTeam) .WithMany(t => t.AwayMatches) .HasForeignKey(m => m.GuestTeamId) .WillCascadeOnDelete(false); } } 

Las claves principales se asignan por convención predeterminada. El equipo debe tener dos colecciones de partidos. No puede tener una sola colección referenciada por dos FK. Match se asigna sin eliminar en cascada porque no funciona en estas referencias múltiples de muchos a muchos.

También es posible especificar el atributo ForeignKey() en la propiedad de navegación:

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

De esta forma, no necesita agregar ningún código al método OnModelCreate

Sé que es una publicación de varios años y puede resolver su problema con la solución anterior. Sin embargo, solo quiero sugerir el uso de InverseProperty para alguien que aún lo necesite. Al menos no necesita cambiar nada en OnModelCreating.

El código siguiente no está probado.

 public class Team { [Key] public int TeamId { get; set;} public string Name { get; set; } [InverseProperty("HomeTeam")] public virtual ICollection HomeMatches { get; set; } [InverseProperty("GuestTeam")] public virtual ICollection 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; } } 

Puede leer más acerca de InverseProperty en MSDN: https://msdn.microsoft.com/en-us/data/jj591583?f=255&MSPPError=-2147217396#Relationships

Usted puede intentar esto también:

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

Cuando haces que una columna FK permita NULLS, estás rompiendo el ciclo. O simplemente estamos engañando al generador de esquema EF.

En mi caso, esta simple modificación resuelve el problema.

Esto se debe a que las eliminaciones en cascada están habilitadas por defecto. El problema es que cuando se llama a una eliminación en la entidad, también se eliminará cada una de las entidades de referencia de la tecla f. No debe hacer que los valores ‘obligatorios’ sean nulos para solucionar este problema. Una mejor opción sería eliminar la convención de eliminación de cascadas de EF Code First:

 modelBuilder.Conventions.Remove(); 

Probablemente sea más seguro indicar explícitamente cuándo hacer una eliminación en cascada para cada uno de los niños al mapear / configurar. la entidad.