首页 文章

实体框架代码中的许多关系首先使用“虚拟”关键字相互访问

提问于
浏览
4

此摘录代码使用显式Junction表成功创建 many-many 关系,其中包含其他数据 .

问题: I want to be able to access Courses from Student and vice versa,
(因此注释了 virtual 属性 . 但如果我取消注释它,它会导致错误(见下文))

如果我没有显式创建联结表(没有其他数据),则虚拟关键字可以正常工作,因为EF会按惯例创建联结表 .

题:

如何在不通过注册的情况下让学生访问课程?或者那是不可能的?如果不可能,那么最好的方法是什么呢?

(EF和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<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }

        public void Run()
        {
            Database.SetInitializer(new DropCreateDatabaseAlways<ManyMany1>());
            this.Courses.Add(new Course() {CourseName = "English"});
            this.SaveChanges();
        }
    }

当我解除公共虚拟......

错误:"Unable to determine the principal end of an association between the types 'EF.Course' and 'EF.Student'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations."

2 回答

  • 11
    public class Student
    {
        public virtual int StudentId { get; set; }
        public virtual string StudentName { get; set; }
    
        public virtual ICollection<Enrollment> Enrollments { get; set; }
    }
    
    public class Course
    {
        public virtual int CourseId { get; set; }
        public virtual string CourseName { get; set; }
    
        public virtual ICollection<Enrollment> 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<Student> Students { get; set; }
        public DbSet<Course> Courses { get; set; }
        public DbSet<Enrollment> Enrollments { get; set; }
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>()
                .HasKey(student => student.StudentId);
            modelBuilder.Entity<Course>()
                .HasKey(course => course.CourseId);
            modelBuilder.Entity<Enrollment>()
                .HasKey(enrollment => new { enrollment.StudentId, enrollment.CourseId } );
    
            modelBuilder.Entity<Student>()
                .HasMany(student => student.Enrollments)
                .WithRequired(enrollment => enrollment.Student)
                .HasForeignKey(enrollment => enrollment.StudentId);
            modelBuilder.Entity<Course>()
                .HasMany(course => course.Enrollments)
                .WithRequired(enrollment => enrollment.Course)
                .HasForeignKey(enrollment => enrollment.CourseId);
        }
    }
    

    关于这个问题的老问题,答案和更多信息:Entity Framework CodeFirst many to many relationship with additional information .

    编辑:用法示例:

    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));
    
  • 5

    实体框架可以't automatically determine '多对多'关系,因为它们是在SQL的其他表的帮助下表达的(在您的情况下是 Enrollment 表) . 您可以直接在 OnModelCreating 方法中指定映射:

    public class YourDbContext : DbContext
    {
        ....
    
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Student>().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
                });
        }
    }
    

    另外,请注意,如果实体有许多其他实体,请使用集合进行关系:

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

相关问题