diff --git a/hibernate-hw.iml b/hibernate-hw.iml index d956b3c..99a49d3 100644 --- a/hibernate-hw.iml +++ b/hibernate-hw.iml @@ -1,5 +1,5 @@ - + @@ -10,47 +10,4 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/pom.xml b/pom.xml index 595ab88..accbcde 100644 --- a/pom.xml +++ b/pom.xml @@ -55,8 +55,8 @@ maven-compiler-plugin 3.3 - 11 - 11 + 15 + 15 UTF-8 diff --git a/src/main/java/ru/hh/school/dao/EmployerDao.java b/src/main/java/ru/hh/school/dao/EmployerDao.java index 0a0d46d..37bf24f 100644 --- a/src/main/java/ru/hh/school/dao/EmployerDao.java +++ b/src/main/java/ru/hh/school/dao/EmployerDao.java @@ -10,7 +10,7 @@ public EmployerDao(SessionFactory sessionFactory) { } /** - * TODO: здесь нужен метод, позволяющий сразу загрузить вакасии, связанные с работодателем и в некоторых случаях + * Здесь нужен метод, позволяющий сразу загрузить вакасии, связанные с работодателем и в некоторых случаях * избежать org.hibernate.LazyInitializationException * Также в запрос должен передаваться параметр employerId *

@@ -18,8 +18,12 @@ public EmployerDao(SessionFactory sessionFactory) { */ public Employer getEager(int employerId) { return getSession() - .createQuery("from Employer employer", Employer.class) + .createQuery( + """ + FROM Employer employer LEFT JOIN FETCH employer.vacancies + WHERE employer.id = :id + """, Employer.class) + .setParameter("id", employerId) .getSingleResult(); } - } diff --git a/src/main/java/ru/hh/school/dao/GenericDao.java b/src/main/java/ru/hh/school/dao/GenericDao.java index 70aa8bc..c577076 100644 --- a/src/main/java/ru/hh/school/dao/GenericDao.java +++ b/src/main/java/ru/hh/school/dao/GenericDao.java @@ -4,8 +4,6 @@ import org.hibernate.SessionFactory; import java.io.Serializable; -import java.util.Collection; -import java.util.Objects; public class GenericDao { private final SessionFactory sessionFactory; @@ -25,7 +23,7 @@ public void save(Object object) { if (object == null) { return; } - getSession().save(object); + getSession().saveOrUpdate(object); } protected Session getSession() { diff --git a/src/main/java/ru/hh/school/dao/VacancyDao.java b/src/main/java/ru/hh/school/dao/VacancyDao.java index 195d045..004abef 100644 --- a/src/main/java/ru/hh/school/dao/VacancyDao.java +++ b/src/main/java/ru/hh/school/dao/VacancyDao.java @@ -10,11 +10,14 @@ public VacancyDao(SessionFactory sessionFactory) { } public StatisticsDto getSalaryStatistics(Area area){ - // ToDo дополните запрос, чтобы возвращался ru.hh.school.employers.StatisticsDto + // Дополните запрос, чтобы возвращался ru.hh.school.employers.StatisticsDto // https://vladmihalcea.com/the-best-way-to-map-a-projection-query-to-a-dto-with-jpa-and-hibernate/ return getSession().createQuery( - "SELECT count(v.id), min(v.compensationFrom), max(v.compensationTo) " + - "FROM Vacancy v WHERE v.area = :area", StatisticsDto.class) + """ + SELECT new ru.hh.school.employers.StatisticsDto( + count(v.id), min(v.compensationFrom), max(v.compensationTo)) + FROM Vacancy v WHERE v.area = :area + """, StatisticsDto.class) .setParameter("area", area) .getSingleResult(); } diff --git a/src/main/java/ru/hh/school/entity/Area.java b/src/main/java/ru/hh/school/entity/Area.java index 2288dd9..ce6e710 100644 --- a/src/main/java/ru/hh/school/entity/Area.java +++ b/src/main/java/ru/hh/school/entity/Area.java @@ -1,11 +1,23 @@ package ru.hh.school.entity; -//TODO: оформите entity +import javax.persistence.*; + +//Оформите entity. +@Entity +@Table(name = "area") public class Area { + @Id + @Column(name = "area_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; + @OneToOne(mappedBy = "area", cascade = CascadeType.ALL) + private Vacancy vacancy; + + @Column(nullable = false) private String name; + public Area() {} public String getName() { return name; } diff --git a/src/main/java/ru/hh/school/entity/Employer.java b/src/main/java/ru/hh/school/entity/Employer.java index 152a66c..ec78de7 100644 --- a/src/main/java/ru/hh/school/entity/Employer.java +++ b/src/main/java/ru/hh/school/entity/Employer.java @@ -1,23 +1,33 @@ package ru.hh.school.entity; +import javax.persistence.*; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; import java.util.Objects; -//TODO: оформите entity +// Оформите entity +@Entity +@Table(name = "employer") public class Employer { + @Id + @Column(name = "employer_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; + @Column(name = "company_name", nullable = false) private String companyName; // не используйте java.util.Date // https://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/Hibernate_User_Guide.html#basic-datetime-java8 + @Column(name = "creation_time") private LocalDateTime creationTime; + @OneToMany(mappedBy = "employer", cascade = CascadeType.ALL) private List vacancies = new ArrayList<>(); + @Column(name = "block_time") private LocalDateTime blockTime; public List getVacancies() { diff --git a/src/main/java/ru/hh/school/entity/Resume.java b/src/main/java/ru/hh/school/entity/Resume.java index 7310dda..f4daed9 100644 --- a/src/main/java/ru/hh/school/entity/Resume.java +++ b/src/main/java/ru/hh/school/entity/Resume.java @@ -1,26 +1,28 @@ package ru.hh.school.entity; -import javax.persistence.GeneratedValue; -import javax.persistence.Id; +import javax.persistence.*; -//TODO: оформите entity +// Оформите entity +@Entity +@Table(name = "resume") public class Resume { - // TODO: сделать так, чтобы id брался из sequence-а + // Сделать так, чтобы id брался из sequence-а // таким образом, мы сможем отправлять в бд запросы батчами. // нужно учитывать, что описание sequence при создании таблицы также должно соответствовать // хиберовской сущности (см. create_resume.sql) // // Подробнее: - // https://vladmihalcea.com/how-to-batch-insert-and-update-statements-with-hibernate/ + // https://vladmihalcea.com /how-to-batch-insert-and-update-statements-with-hibernate/ // https://vladmihalcea.com/from-jpa-to-hibernates-legacy-and-enhanced-identifier-generators/ @Id - @GeneratedValue(/* здесь место для вашего кода */) + @GeneratedValue(generator = "resume_id_seq", strategy = GenerationType.SEQUENCE) + @SequenceGenerator(name = "resume_id_seq", allocationSize = 10) private Integer id; private String description; - Resume() {} + public Resume() {} public Resume(String description) { this.description = description; diff --git a/src/main/java/ru/hh/school/entity/Vacancy.java b/src/main/java/ru/hh/school/entity/Vacancy.java index 8d017b4..2508b93 100644 --- a/src/main/java/ru/hh/school/entity/Vacancy.java +++ b/src/main/java/ru/hh/school/entity/Vacancy.java @@ -1,38 +1,45 @@ package ru.hh.school.entity; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.Table; +import javax.persistence.*; import java.time.LocalDateTime; import java.util.Objects; -//TODO: оформите entity +// Оформите entity +@Entity +@Table(name = "vacancy") public class Vacancy { + @Id + @Column(name = "vacancy_id") + @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "employer_id", nullable = false) private Employer employer; + @OneToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "area_id") private Area area; + @Column(nullable = false) private String title; private String description; + @Column(name = "compensation_from") private Integer compensationFrom; + @Column(name = "compensation_to") private Integer compensationTo; + @Column(name = "compensation_gross") private Boolean compensationGross; + @Column(name = "creation_time") private LocalDateTime creationTime; + @Column(name = "archiving_time") private LocalDateTime archivingTime; public Vacancy() { diff --git a/src/main/java/ru/hh/school/service/EmployerService.java b/src/main/java/ru/hh/school/service/EmployerService.java index 4822f0d..680b8c0 100644 --- a/src/main/java/ru/hh/school/service/EmployerService.java +++ b/src/main/java/ru/hh/school/service/EmployerService.java @@ -60,15 +60,17 @@ public void blockIfEmployerUseBadWords(int employerId) { return; } - // TODO: сделать сохранение состояния работодателя и его вакансий + // Сделать сохранение состояния работодателя и его вакансий // сейчас Employer в detached состоянии, т.к. сессия закрылась. // это нужно учитывать при последующей работе с таковым // про состояния: https://vladmihalcea.com/a-beginners-guide-to-jpa-hibernate-entity-state-transitions/ // про возврат в managed состояние: https://vladmihalcea.com/jpa-persist-and-merge + transactionHelper.inTransaction(() -> { employer.setBlockTime(LocalDateTime.now()); employer.getVacancies().forEach(v -> v.setArchivingTime(LocalDateTime.now())); + genericDao.save(employer); }); } diff --git a/src/test/java/ru/hh/school/batching/BatchingTest.java b/src/test/java/ru/hh/school/batching/BatchingTest.java index a329e60..b083ab3 100644 --- a/src/test/java/ru/hh/school/batching/BatchingTest.java +++ b/src/test/java/ru/hh/school/batching/BatchingTest.java @@ -23,7 +23,7 @@ public void clearTable() { } /** - * ToDo доконфигурируйте ru.hh.school.batching.Resume + * Доконфигурируйте ru.hh.school.batching.Resume * * @see scripts/create_resume.sql * и hibernate.properties (раздел batch processing)