Relación de muchos a muchos en Entity Framework Code First y usando la palabra clave “virtual” para acceder entre sí

Este código de extracto crea con éxito una relación de muchos con una tabla de conexiones explícita que tiene datos adicionales dentro de ella.

PROBLEMA: Quiero poder acceder a los Cursos de Estudiantes y viceversa,
(Por lo tanto, la propiedad virtual comentada. Pero si la descomprimo, se produce un error (ver más abajo))

Si no creo explícitamente una tabla de unión (sin datos adicionales), la palabra clave virtual funciona aunque EF crea una tabla de unión por convención.

PREGUNTA:

¿Cómo puedo hacer que los alumnos accedan a los cursos sin pasar por las inscripciones? ¿O es que eso no es posible? Si no es posible, ¿cuál es la mejor manera de hacerlo?

( un principiante en EF y C # )

public class Student { [Key] public int StudentId { get; set; } public string StudentName { get; set; } //public virtual Course Courses { get; set; } } public class Course { [Key] public int CourseId { get; set; } public string CourseName { get; set; } //public virtual Student Students { get; set; } } public class Enrollment { [Key] public int EnrollmentId { get; set; } public Student Student { get; set; } public Course Course { get; set; } public string Grade { get; set; } } public class ManyMany : DbContext, IContext { public DbSet Students { get; set; } public DbSet Courses { get; set; } public DbSet Enrollments { get; set; } public void Run() { Database.SetInitializer(new DropCreateDatabaseAlways()); this.Courses.Add(new Course() {CourseName = "English"}); this.SaveChanges(); } } 

CUANDO ME DESCOMPRENDO publico virtual …

ERROR: “No se puede determinar el final principal de una asociación entre los tipos ‘EF.Course’ y ‘EF.Student’. El final principal de esta asociación debe configurarse explícitamente mediante la relación fluida API o las anotaciones de datos”.

 public class Student { public virtual int StudentId { get; set; } public virtual string StudentName { get; set; } public virtual ICollection Enrollments { get; set; } } public class Course { public virtual int CourseId { get; set; } public virtual string CourseName { get; set; } public virtual ICollection Enrollments { get; set; } } public class Enrollment { public virtual int StudentId { get; set; } public virtual int CourseId { get; set; } public virtual string Grade { get; set; } public virtual Student Student { get; set; } public virtual Course Course { get; set; } } public class ManyMany : DbContext { public DbSet Students { get; set; } public DbSet Courses { get; set; } public DbSet Enrollments { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity() .HasKey(student => student.StudentId); modelBuilder.Entity() .HasKey(course => course.CourseId); modelBuilder.Entity() .HasKey(enrollment => new { enrollment.StudentId, enrollment.CourseId } ); modelBuilder.Entity() .HasMany(student => student.Enrollments) .WithRequired(enrollment => enrollment.Student) .HasForeignKey(enrollment => enrollment.StudentId); modelBuilder.Entity() .HasMany(course => course.Enrollments) .WithRequired(enrollment => enrollment.Course) .HasForeignKey(enrollment => enrollment.CourseId); } } 

Pregunta más antigua sobre esto, respuesta y más información aquí: Entity Framework CodeFirst muchas a muchas relaciones con información adicional .

EDITAR: Ejemplo de uso:

  var context = new ManyMany(); var physicsCourse = new Course() { CourseName = "Physics" }; var mathCourse = new Course() { CourseName = "Math" }; var studentJohn = new Student() { StudentName = "John Doe" }; var studentJane = new Student() { StudentName = "Jane Doe" }; var physicsCourseEnrollmentJohn = new Enrollment() { Student = studentJohn, Course = physicsCourse }; var mathCourseEnrollmentJohn = new Enrollment() { Student = studentJohn, Course = mathCourse }; var physicsCourseEnrollmentJane = new Enrollment() { Student = studentJane, Course = physicsCourse }; context.Courses.Add(physicsCourse); context.Courses.Add(mathCourse); context.Students.Add(studentJohn); context.Students.Add(studentJane); studentJohn.Enrollments.Add(physicsCourseEnrollmentJohn); studentJohn.Enrollments.Add(mathCourseEnrollmentJohn); studentJane.Enrollments.Add(physicsCourseEnrollmentJane); physicsCourse.Enrollments.Add(physicsCourseEnrollmentJohn); mathCourse.Enrollments.Add(mathCourseEnrollmentJohn); physicsCourse.Enrollments.Add(physicsCourseEnrollmentJane); context.Enrollments.Add(physicsCourseEnrollmentJohn); context.Enrollments.Add(mathCourseEnrollmentJohn); context.Enrollments.Add(physicsCourseEnrollmentJane); context.SaveChanges(); var johnsEnrollments = context.Students.Where(student => student.StudentId == studentJohn.StudentId).Single().Enrollments; MessageBox.Show(string.Format("Student John has enrolled in {0} courses.", johnsEnrollments.Count)); var janesEnrollments = context.Students.Where(student => student.StudentId == studentJane.StudentId).Single().Enrollments; MessageBox.Show(string.Format("Student Jane has enrolled in {0} courses.", janesEnrollments.Count)); 

Entity Framework no puede determinar automáticamente las relaciones ‘muchos a muchos’ porque se expresan con la ayuda de tablas adicionales en SQL (en su caso, es Enrollment tabla de Enrollment ). Puede especificar asignaciones directamente en el método OnModelCreating :

 public class YourDbContext : DbContext { .... protected override void OnModelCreating(DbModelBuilder modelBuilder) { modelBuilder.Entity().HasMany(x => x.Courses).WithMany(x => x.Students) .Map(m => { m.ToTable("Enrollment"); // Relationship table name m.MapLeftKey("StudentID"); // Name of column for student IDs m.MapRightKey("CourseID"); // Name of column for course IDs }); } } 

Además, tome nota de que si una entidad tiene muchas otras entidades, use la recostackción para la relación:

 public class Student { .... public virtual ICollection Courses { get; set; } // Many courses } public class Course { .... public virtual ICollection Students { get; set; } // Many students }