Spring Boot Bootcamp – Workbooks and Challenges
)}

Challenge

There is a Many to Many relationship between the course and student tables.

Launch the Starter Project

Screen Shot 2022-08-06 at 4.58.09 PM.png

One to Many

One student can have Many grades. Many grades belong to One student.

Screen Shot 2022-08-06 at 5.03.20 PM.png

The student_id column joins both tables.

Screen Shot 2022-08-06 at 5.19.09 PM.png

One to Many

One course can have Many grades. Many grades belong to One course.

Screen Shot 2022-08-06 at 5.07.32 PM.png

The course_id column joins both tables.

Screen Shot 2022-08-06 at 5.20.45 PM.png

Many to Many

One student can enroll in Many courses. One course can contain Many students.

Screen Shot 2022-08-06 at 6.20.07 PM.png

The course_student table joins both tables.

Harry took four courses.

Screen Shot 2022-08-07 at 11.25.57 PM.png

Hermione took four courses.

Screen Shot 2022-08-06 at 6.21.04 PM.png

Herbology contains three students.

Screen Shot 2022-08-06 at 6.21.51 PM.png

Alchemy contains four students.

Screen Shot 2022-08-06 at 6.22.45 PM.png

The table that joins course and student is called a Join Table.

Task 1

Inside Course, declare a @ManyToMany relationship with a List of students.

@ManyToMany private List<Student> students;

Task 2

Inside Student, declare a @ManyToMany relationship with a List of courses.

Who will own the association?

In the One to Many relationship between student and grade, the foreign key lives inside grade.

Screen Shot 2022-08-06 at 5.19.09 PM.png

As a result, grade owns the association.

@Table(name = "grade") public class Grade { @ManyToOne @JoinColumn(name = "student_id", referencedColumnName = "id") private Student student; }

In the One to Many relationship between course and grade, the foreign key column lives inside grade.

Screen Shot 2022-08-06 at 5.20.45 PM.png

As a result, grade owns the association.

@Table(name = "grade") public class Grade { @ManyToOne @JoinColumn(name = "student_id", referencedColumnName = "id") private Student student;

In a Many to Many relationship, the joining columns live inside of the join table.

Screen Shot 2022-08-06 at 6.42.32 PM.png

So it doesn't matter who owns the association.

Task 3

For the sake of this exercise, Course will own the association. Followed by its @ManyToMany annotation, define a @JoinTable.

Screen Shot 2022-08-06 at 7.02.12 PM.png

  1. Set the name equal to course_student

The parameters that follow define the join table's foreign key columns. Each foreign key column references the primary key of one table.

Screen Shot 2022-08-18 at 4.53.55 PM.png

  1. Set joinColumns equal to a foreign key column @JoinColumn that references the primary table of the entity owning the association.
  2. Set inverseJoinColumns equal to a foreign key column @JoinColumn that references the primary table of the entity that does not own the association.

Expected output


Screen Shot 2022-08-08 at 12.03.05 AM.png

The course_student join table appears, but Spring Boot creates another one by default.

Task 4

Place the mappedBy parameter on the non-owning side of the relationship.

Expected output


Screen Shot 2022-08-15 at 11.44.58 PM.png

Task 5

In order to avoid a recursive loop, add @JsonIgnore to at least one side of the relationship. For this exercise, add it to the non-owning side.

@JsonIgnore @ManyToMany(mappedBy = "students") private List<Course> courses;

Task 6

Inside the CourseServiceImpl, finish writing the code for addStudentToCourse:

//TODO... course.getStudents().add(unwrappedStudent); return courseRepository.save(course);

Task 7

Inside the CourseController, finish writing the code for enrollStudentToCourse.

Task 8

From Postman, create a new PUT request under the Course folder.

Screen Shot 2022-08-08 at 12.38.46 AM.png

Make four PUT requests to localhost:8080/course/1/student/(1 to 4).

Postman Output

{ "id": 1, "subject": "Charms", "code": "CH104", "description": "In this class, you will learn spells concerned with giving an object new and unexpected properties.", "students": [ { "id": 2, "name": "Ron Weasley", "birthDate": "1980-03-01" }, { "id": 3, "name": "Hermione Granger", "birthDate": "1979-09-19" }, { "id": 4, "name": "Neville Longbottom", "birthDate": "1980-07-30" }, { "id": 1, "name": "Harry Potter", "birthDate": "1980-07-31" } ] }

H2 Output

Screen Shot 2022-08-07 at 12.14.40 AM.png

Task 9

Currently, you can assign a course duplicate students. Try adding Ron to Charms twice.

Screen Shot 2022-08-08 at 1.14.36 AM.png

In both POJO classes, replace the List collection type with a Set. A Set is a collection type that prevents the addition of duplicate elements. A student cannot enroll in duplicate courses.

private Set<Course> courses;

Similarly, a course cannot contain duplicate students.

private Set<Student> students;

Once again, test your application by trying to duplicate Ron's enrollment in charms.

Task 10

  • Inside CourseServiceImpl, finish writing the getEnrolledStudents() method.
  • Inside CourseController, finish writing the getEnrolledStudents() handler method.
  • Inside StudentServiceImpl, finish writing the getEnrolledCourses() method.
  • Inside StudentController, finish writing the getEnrolledCourses() handler method.

Task 11

  1. From Postman, create a new GET request under the Student folder.

Screen Shot 2022-08-07 at 1.14.34 AM.png

  1. From Postman, create a new GET request under the Course folder.

Screen Shot 2022-08-07 at 1.17.07 AM.png

Task 12

Whenever we query a course, we want to exclude the collection of students from the JSON. Otherwise, the response will be messy and convoluted. Put the @JSONIgnore annotation on the owner side too.

@JsonIgnore @ManyToMany @JoinTable( name = "course_student", joinColumns = @JoinColumn(name = "course_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "student_id", referencedColumnName = "id") ) private Set<Student> students;

Task 13

Make 12 PUT requests:

  • Enroll Harry in Charms and Potions.
  • Enroll Ron in History of Magic and Transfiguration
  • Enroll Hermione in Charms, History of Magic, Potions, and Transfiguration
  • Enroll Neville in Charms, Potions, and Herbology.
localhost:8080/course/1/student/1
localhost:8080/course/5/student/1

localhost:8080/course/4/student/2
localhost:8080/course/6/student/2

localhost:8080/course/1/student/3
localhost:8080/course/4/student/3
localhost:8080/course/5/student/3
localhost:8080/course/6/student/3


localhost:8080/course/1/student/4
localhost:8080/course/5/student/4
localhost:8080/course/3/student/4

Output

Screen Shot 2022-08-07 at 12.33.42 AM.png

From Postman, read all of the courses that Harry is enrolled in:

[ { "id": 1, "subject": "Charms", "code": "CH104", "description": "In this class, you will learn spells concerned with giving an object new and unexpected properties." }, { "id": 5, "subject": "Potions", "code": "POT102", "description": "In this class, you will learn correct mixing and stirring of ingredients to create mixtures with magical effects." } ]

From Postman, read all of the courses that Hermione is enrolled in:

[ { "id": 1, "subject": "Charms", "code": "CH104", "description": "In this class, you will learn spells concerned with giving an object new and unexpected properties." }, { "id": 4, "subject": "History of Magic", "code": "HIS393", "description": "In this class, you will learn about significant events in wizarding history." }, { "id": 6, "subject": "Transfiguration", "code": "TR442", "description": "In this class, you will learn the art of changing the form or appearance of an object." }, { "id": 5, "subject": "Potions", "code": "POT102", "description": "In this class, you will learn correct mixing and stirring of ingredients to create mixtures with magical effects." } ]

From Postman, read all of the students enrolled in Potions.

[ { "id": 1, "name": "Harry Potter", "birthDate": "1980-07-31" }, { "id": 3, "name": "Hermione Granger", "birthDate": "1979-09-19" }, { "id": 4, "name": "Neville Longbottom", "birthDate": "1980-07-30" } ]

Task 14

Inside GradeServiceImpl.saveGrade(), throw a new StudentNotEnrolledException() if the client assigns a student a grade on a course they are not enrolled in.

@Override public Grade saveGrade(Grade grade, Long studentId, Long courseId) { Student student = studentRepository.findById(studentId).get(); Course course = courseRepository.findById(courseId).get(); //TODO: if student not enrolled in course, throw StudentNotEnrolledException grade.setStudent(student); grade.setCourse(course); return gradeRepository.save(grade); }

Handle the exception by adding StudentNotEnrolledException.class as an argument for the @ExceptionHandler: handleResourceNotFoundException.

Task 15

Enroll Harry in Charms. Then, give him an A+.

{ "id": 1, "score": "A+", "student": { "id": 1, "name": "Harry Potter", "birthDate": "1980-07-31" }, "course": { "id": 1, "subject": "Charms", "code": "CH104", "description": "In this class, you will learn spells concerned with giving an object new and unexpected properties." } }

Now, give him a grade on a course that he's not enrolled in.

{ "timestamp": "07-08-2022 01:03:57", "message": [ "The student with id: '1' is not enrolled in the course with id: '2" ] }

Good Luck!

Feedback Summary
5.0
3 students
5

100%
4

0%
3

0%
2

0%
1

0%
Written Reviews
There are no written reviews yet.