简体   繁体   中英

update data in the junction table

ASP.Net Core vs MySQL

Student table and Course table are joined with the junction table StudentCourse:

Student      StudentCourse       Course
=========    ============        =======
PK | ID      FK | StudentID       PK | ID
   | Name    FK | CourseID           | Name

A student changes his course so manager needs to change CourseID in the junction table StudentCourse.

But I don't have direct access to the junction table due to:

public class AppDbContext
{
    public DbSet<CourseModel> CourseModels { get; set; }
    public DbSet<StudentModel> StudentModels { get; set; }

    protected override void OnModelCreating(ModelBuilder builder)
    {
        base.OnModelCreating(builder);

        builder.Entity<StudentCourse>()
            .HasKey(t => new { t.StudentId, t.CourseId });

        builder.Entity<StudentCourse>()
            .HasOne(sc => sc.Student)
            .WithMany(s => s.StudentCourse)
            .HasForeignKey(sc => sc.StudentId);

        builder.Entity<StudentCourse>()
            .HasOne(sc => sc.Course)
            .WithMany(s => s.StudentCourse)
            .HasForeignKey(sc => sc.CourseId);
    }
}

So I can't execute this SQL command directly:

UPDATE StudentCourse SET CourseId = '9A414E30-DA37-48ED-105E-08D8129A967A' WHERE StudentId = 'A1F38C12-AE65-464C-C489-08D814F4CDDC'

I think I have to use Inner Join. My logic is:

    [HttpGet]
    public IActionResult ChangeCourse(Guid id)
    {
        IQueryable<CourseModel> courses = courseModel.GetCourses();
        ViewBag.Courses = new SelectList(courses, "Id", "Name");

        var course = courseModel.GetCourseById(id);

        return View(course);
    }

    [HttpPost]
    public IActionResult ChangeCourse(CourseModel newCourse)
    {
        // I know student's id, so I can get his old course id
        Guid oldCourseId = (from ... in ...).SingleOrDefault();
        // Then just change and save
        oldCourseId = newCourse.Id;
        context.SaveChanges();

        return RedirectToAction();
    }

I have the SQL command to get an old course id:

SELECT CourseId FROM StudentModels L
INNER JOIN StudentCourse R
ON L.Id = R.StudentId
WHERE L.Id = 'A1F38C12-AE65-464C-C489-08D814F4CDDC'

So the questions are:

  1. Are my assumptions correct?
  2. How to write this SQL command in LINQ?

I tried this but got the list of Ids:

from student in context.StudentModels join cours in context.CourseModels on student.Id equals studentId select cours.Id

I'm not good at LINQ, yet. Please help.

There seems to be a many-to-many relation between Students and Courses. Every Student follows zero or more Courses, and every Course is followed by zero or more Students. That why you need a junction table

You wrote:

A student changes his course

Well, as Students can follow several Courses, you cannot say that a Student changes his course. You can say that a Student follows a new Course, and/or stops following another Course.

If you have followed the entity framework conventions, you will have classes similar to the following:

class Student
{
    public int Id {get; set;}
    ...

    // Every Student follows zero or more Courses (many-to-many)
    public virtual ICollection<Course> Courses {get; set;}
}

class Course
{
    public int Id {get; set;}
    ...

    // Every Course is followed by zero or more Courses (many-to-many)
    public virtual ICollection<Student> Students {get; set;}
}

This is all entity framework needs to know to detect your many-to-many relationship. It will automatically create a junction table for you and use it whenever needed.

If you want to change any item in entity framework, you'll have to fetch the complete item, and use Include for related Collections

To Stop following a course and start following a new Course:

int studentId = ...
int courseIdToStop = ...
int courseIdToAttend = ...

// get the student to change; include his courses
Student studentToChange = dbContext.Students
    .Include(student => student.Courses)
    .Where(student => student.Id == studentId)
    .FirstOrDefault();


// Stop the course
Course courseToStop = studentToChange.Courses
    .Where(course => course.Id == courseIdToStop)
    .FirstOrDefault();

if (courseToStop != null)
{
    // This Student follows this cours; stop it:
    studentToChange.Courses.Remove(courseToStop);
}

Course courseToStart = dbContext.Courses
    .Where(course => course.Id == courseIdToStart)
    .FirstOrDefault();

// only start the course if course exists and not already following
if (courseToStart != null && !studentToChange.Courses.Contains(courseToStart))
{
    studentToChange.Courses.Add(courseToStart);
}

dbContext.SaveChanges();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM