0

This question is in reference to the project discussed here. After resolving the previous problem I have run into a new one. When The Student object is saved, the list of courses associated with it is not saved. I can see the collection of course objects when I mouse over the student object after setting a breakpoint:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult AddCourseVM (AddCourseViewModel vModel)
    {
        Student stu = db.Students.Find(vModel.Student.ID);
        foreach (Course c in vModel.PossibleCourses)
        {
            if (c.Selected)
            {
                BaseCourse bc = db.BaseCourses.Find(c.BaseCourse.ID);
                c.BaseCourse = bc;
                c.Student = stu;
                stu.CoursesTaken.Add(c);
            }
        }

        if (stu != null)
        {
            db.Entry(stu).State = EntityState.Modified; //breakpoint here
            db.SaveChanges();
        }

        return RedirectToAction("ListTakenCourses", stu);
    }

    public ActionResult ListTakenCourses (Student stu)
    {
        List<Course> taken = stu.CoursesTaken.ToList();
        foreach (Course c in taken)
        {
            c.BaseCourse = db.BaseCourses.Find(c.BaseCourse.ID);
        }
        ViewBag.CoursesTaken = taken;

        return View(stu);
    }

But when I pass the object to the next method, the list of courses taken comes back null. The courses are being saved to the database, I can see them when I go into the SQL Server explorer, but for some reason they are not being attached to the student object. The code for the objects:

public class Student
{
    public int ID { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string WNumber { get; set; }
    public int HoursCompleted { get; set; }
    public double GPA { get; set; }

    public Concentration StudentConcentration { get; set; }

    public virtual ICollection<Course> CoursesTaken { get; set; }
    public virtual ICollection<Course> CoursesRecommended { get; set; }

}

and:

public class Course
{
    public int ID { get; set; }
    public string Semester { get; set; }
    public Grade? Grade { get; set; }
    public bool Selected { get; set; }

    public BaseCourse BaseCourse { get; set; }
    public Student Student { get; set; }

}

Something that may be important, but that I don't really understand: when I look at the table for the Course object in the database, there are three columns, called Student_ID, Student_ID1, and Student_ID2. I assume they relate to the student associated with the object and the two ways it can be associated (recommended or taken), but the odd thing is that Student_ID is always null, while the other two sometimes have a value and sometimes do not. I have not even begun to implement the recommendation process, so there is no way that list is being filled.

I reworked the classes and now it seems to be working. I changed the Course object to:

 public class Course
{
    public int ID { get; set; }
    public string Semester { get; set; }
    public Grade? Grade { get; set; }
    public bool Selected { get; set; }
    public int BaseCourseID { get; set; }
    public int StudentID { get; set; }

    public BaseCourse BaseCourse { get; set; }
    public Student Student { get; set; }

}

and the controller methods to:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult AddCourseVM (AddCourseViewModel vModel)
    {
        Student stu = db.Students.Find(vModel.Student.ID);
        foreach (Course c in vModel.PossibleCourses)
        {
            if (c.Selected)
            {
                BaseCourse bc = db.BaseCourses.Find(c.BaseCourse.ID);
                c.BaseCourse = bc;
                c.Student = stu;
                stu.CoursesTaken.Add(c);
                db.Entry(c).State = EntityState.Added;
            }
        }

        if (stu != null)
        {
            db.Entry(stu).State = EntityState.Modified;
            db.SaveChanges();
        }

        return RedirectToAction("ListTakenCourses", stu);
    }

    public ActionResult ListTakenCourses (Student stu)
    {
        List<Course> taken = db.Courses.Where(c => c.StudentID == stu.ID).ToList();
        foreach (Course c in taken)
        {
            c.BaseCourse = db.BaseCourses.Find(c.BaseCourseID);
            c.Student = stu;
            stu.CoursesTaken.Add(c);
        }
        ViewBag.CoursesTaken = taken;

        return View(stu);
    }

And it is now displaying the courses I add on the next page, but it seems odd that I have to save the child objects separately from the parent and that I have to get the list from the database manually instead of being able to use the object structure. Is this intended behavior, or is there a better way of doing what I'm trying to do (add a list of child objects (courses) to a student object, save the relationship to the database, and then display the list of added objects)?

Community
  • 1
  • 1
jchancey
  • 25
  • 1
  • 5
  • I think you should restore the question to its first version, accept Erik's answer (since it clearly helped you) and ask a new question about the second issue. – Gert Arnold Mar 01 '15 at 23:00

1 Answers1

1

You are not "passing the object to the next method". You are serializing the object and passing it on the URL, then deserializing it on the other end with this method:

return RedirectToAction("ListTakenCourses", stu);

This is not the way to go about things. What you should be doing is passing a single id, such as the student id. Then, in ListTakenCourses you look up the student again in the database, which if you are doing your query correctly will fully populate the objects.

return RedirectToAction("ListTakenCourses", new { id = stu.StudentID });

public ActionResult ListTakenCourses (int id)
{
    List<Course> taken = db.Courses.Where(c => c.StudentID == id).ToList();

    //...
}
Erik Funkenbusch
  • 92,674
  • 28
  • 195
  • 291