The goal of this task is to practice some major JPA concepts on a Postgres database.
Your goal is to design database schema and JPA classes to operate with a university model that will include students, courses, disciplines, and grading.
The task is split into six sections. It's recommended that you complete this task iteratively, section by section; however, this is not required. You can do it all at once if you prefer.
The instructions below refer to both sections and tasks. Keep in mind that these are the same thing in this context.
You are expected to use a Postgres database.
First, you need to install Docker and Docker Compose on your local machine. It'll allow you to run a database instance in an isolated environment.
The easiest way is to install Docker Desktop. You can follow one of those guides based on your OS:
- Windows - https://docs.docker.com/desktop/setup/install/windows-install/
- Linux - https://docs.docker.com/desktop/setup/install/linux/
- Mac - https://docs.docker.com/desktop/setup/install/mac-install/
After you install Docker, check launch Docker Desktop. It must be up and running.
Go to the project directory using command shell (cmd, bash, zsh, etc.) and execute command:
docker-compose startIf everything is successful, you'll see a message
Now you can connect to the database using the configuration:
- port - 55432
- database - mydatabase
- user - myuser
- password - secret
You must provide SQL script(s) that describe your schema. Use the Flyway approach to do this.
- You must put your SQL scripts in the
src/main/resources/db/migrationdirectory. - Each script must have a
.sqlextension. - Each script should start with
Vddd__, wheredis a digit.
To clarify the last point, if you have multiple scripts, they must be ordered.
This Vddd prefix determines this order. So, if you have three scripts, they should be named as follows:
V001__init.sqlV002__adding_somethig.sqlV003__changing_something.sql
Flyway supports different ordering formats, but you should stick to the simplest one.
If you have only one script, name it V001__init.sql.
However, it's recommended to write multiple scripts to practice making gradual changes to a database. However, if you feel this is too hard, it's OK to provide just one script for all the changes.
Your work will mostly involve defining JPA entities mapped on your schema.
So, there will be entities and repositories that encapsulate work with database- and JPA-specific classes,
such as EntityManager or EntityManagerFactory.
All JPA-related classes must go under edu.epam.fop.web.jpa packages.
However, in some cases, it's wise to implement some functionality on the service layer
instead of writing complex SQL queries. It's up to you to decide what approach you want to use
as long as the requirements are met. Feel free to ask your classmates or professors how best to do this.
All services must go under the edu.epam.fop.web.service package.
Also, you'll need to provide demonstration classes (demo-classes).
They will have at least a main method, which demonstrates how your code works.
For each section, you'll need to provide at least one demo-class, but there will be more than that in most cases.
All demo classes must go under edu.epam.fop.web.demos.* packages. The first section should go in the task1 sub-package,
the second in task2, etc.
If a task says that demo-class accepts some parameter, it means that it'll be passed as a program argument. You can get them via an args parameter of a main method. For example, if a task says DemoClass accepts name and id, this class might look like the following:
public class DemoClass {
public static void main(String[] args) {
String name = args[0];
long id = Long.parseLong(args[1]);
doWork(name, id);
}
// there is implementation of doWork
}First, implement a basic scenario for using JPA.
Create two tables:
student- id - bigserial primary key
- name - varchar
- active - boolean
course- id - bigserial primary key
- name - varchar
- active - boolean
Create JPA entities for these tables.
Implement CRUD operations for them in repository classes.
This means that using the StudentRepository class, it's possible to:
Create a new student in a databaseRead student(s) from a databaseUpdate a student in a databaseDelete a student from a database
By default, both students and courses must be inactive.
So, if you create a new student, for example, it must have active = false.
When you have completed the task, the files in these directories should be structured as follows:
- edu.epam.fop.web.jpa
- entity
- Student
- Course
- repository
- StudentRepository
- CourseRepository
- entity
To demonstrate how your code works, you must implement the following demo classes:
CreateCourseDemo- accepts the name of a course and creates a new course with this nameCreateStudentDemo- accepts the name of a student and creates a new student with this nameFindStudentDemo- accepts a student id and prints it to the consoleFindCourseDemo- accepts a course id and prints it to the consoleActivateStudentDemo- accepts a student id and updates itsactivetotrueActivateCourseDemo- accepts a course id and updates itsactivetofalseDeleteStudentDemo- accepts a student id nd deletes itDeleteCourseDemo- accepts a course id and deletes it
You can find these classes under the edu.epam.fop.web.demos.task1 package.
In this section, you'll practice using one-to-many relations between entities.
Create a table
department- id - bigserial primary key
- name - varchar
Update the student table by adding a department_id column with bigint type and references department(id).
For the entities, you need to add a relation between department and student
using @OneToMany and @ManyToOne annotations as well as @JoinColumn.
For department, you must implement a method for creating it. You will treat it as immutable for simplicity's sake,
so no updating or deleting is required.
You need to add methods for:
- Searching for students by department
- Moving a student to a department
By default, a student is created without a department.
Implement demo-classes under the edu.epam.fop.web.demos.task2 package:
CreateDepartmentDemo- accepts the name of a department and creates a new department with this nameMoveStudentToDepartmentDemo– accepts a student id and department and updates this studentdepartment_idcolumn to the passed department id.SearchStudentsByDepartmentDemo- accepts a department id and prints all the students tied to this department to the console
In this section, you'll practice using JPA date-time mapping.
Add the following to the course table fields:
- start_at - timestampz
- end_at - timestampz
Add methods for updating those columns for a course. By default, they are null.
Here is a business explanation of those fields:
- If a course does not have
start_at, it's in draft status, so no validation is required. - If
end_atis null, it's an infinite course with no deadline. - If a course has both
start_atandend_at, it must be validated thatend_atcomes afterstart_at.
That means that the active field of a course can be ignored and that start_at and end_at can be used to determine
if it's active or not. Now, a course is considered active if it has non-null start_at in the past
and end_at either null or in the future.
If a course's start_at is in the future, this course is considered a future course.
Add methods for searching:
- Active courses
- Future courses
Implement demo-classes for task 3:
UpdateCourseStartAtDemo- accepts a course id and a new start_at value and updates it in the databaseUpdateCourseEndAtDemo- accepts a course id and a new start_at value and updates it in the databaseSearchActiveCoursesDemo- prints all active courses to the consoleSearchFutureCoursesDemo- prints all future courses to the console
In this section, you'll practice using many-to-many relations between entities.
Add the table discipline:
- id - bigserial primary key
- name - varchar
You also need to create a join-table discipline_course between course and discipline. It must have the following columns:
- discipline_id - bigint not null
- course_id - bigint not null
The primary key for this table is a combination of those columns: primary key(discipline_id, course_id).
Add an entity for discipline and an update course entity. Both must have @ManyToMany annotation and reference each other.
Add methods for:
- Creating a discipline
- Deleting a discipline
- Creating a relation between a course and a discipline
- Deleting a relation between a course and a discipline
Keep in mind that if you delete disciplines, the courses tied to them must not be deleted and vice versa.
Implement demo-classes in the edu.epam.fop.web.demos.task4 package:
CreateDisciplineDemo- accepts a name and creates a new disciplineDeleteDisciplineDemo- accepts an id and deletes a disciplineLinkCourseDisciplineDemo- accepts course and discipline ids and creates a relation between themUnlinkCourseDisciplineDemo- accepts course and discipline ids and deletes a relation between themSearchDisciplinesForCourseDemo- accepts a course id and prints all the disciplines tied to this courseSearchCoursesOfDisciplineDemo- accepts a discipline id and prints all courses tied to this discipline
In this task, you'll practice mapping a Java enum to database values.
First, you need to add a column named grading to discipline_course. It may be either varchar or int.
If it's int, the default value is 0; otherwise, it's NONE.
Declare enum for the values of this column:
- NONE
- EXAM
- TEST
- REPORT
Create an entity for join-table discipline_course containing grading column using @Enumerated annotation.
EnumType should be ORDINAL for the int grading column and STRING for varchar.
Add methods for:
- Updating the grading type for the course-discipline relation
- Searching disciplines by course and grading type
Implement demo-classes in the edu.epam.fop.web.demos.task5 package:
UpdatingDisciplineCourseRelationDemo– accepts a course and discipline id and grading type. It must update the existing relation between course-discipline and grading.SearchDisciplineByCourseAndGradingDemo- accepts a course id and grading and prints to the console all disciplines that are tied to the course and have the passed grading
In this task, you will practice using transient fields in JPA and bean validation (JSR-380).
Add the table grade:
- student_id - bigint not null references
student(id) - discipline_id - bigint not null references
discipline(id) - value - int null. Allowed values: from 0 to 100 inclusive
Add methods for:
- Adding a relation between student and discipline and grading
- Updating this relation
- Deleting this relation
Create a JPA entity for Grade. On the value field, add @Min and @Max annotations.
Update student with a @OneToMany field for grade. Add a @Transient field for average grade.
This must be updated in the grades setter.
Keep in mind that a student's average grade must be calculated only in Java code and not persisted in the database in any way.
Implement demo-classes in the edu.epam.fop.web.demos.task6 package:
AddingOrUpdatingGradeDemo– accepts a student id, discipline id, and int value for grading and updates or creates a relation between discipline and studentDeletingGradeDemo– accepts a student id and discipline id and deletes the relation between them.
In the end, your schema should look like:

