I found a problem in my project. A have those three entities: CompanyBranch, Department, Employee. Relationship between CompanyBranch and Departmen is One-To-Many, same with Department and Employee. Here my entity classes:
@Entity
@Table(name = "COMPANY_BRANCH", uniqueConstraints = {
@UniqueConstraint(name = "AddressUniqueConstraint", columnNames = {"COMPANY_BRANCH_CITY",
"COMPANY_BRANCH_ZIP_CODE", "COMPANY_BRANCH_STREET", "COMPANY_BRANCH_COUNTRY"})
})
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class CompanyBranch {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@Convert(
converter = MoneyConverter.class
)
@Column(name = "COMPANY_BRANCH_BUDGET", length = 63)
private Money budget;
@Embedded
@NotNull
@AttributeOverrides({
@AttributeOverride(name = "city",
column = @Column(name = "COMPANY_BRANCH_CITY")),
@AttributeOverride(name = "zipCode",
column = @Column(name = "COMPANY_BRANCH_ZIP_CODE")),
@AttributeOverride(name = "street",
column = @Column(name = "COMPANY_BRANCH_STREET")),
@AttributeOverride(name = "country",
column = @Column(name = "COMPANY_BRANCH_COUNTRY"))
})
private Address companyBranchAddress;
@NotNull
@NotBlank(message = "Номер телефона не должен быть пустым")
@Pattern(regexp = "^(\\+\\d{1,3}( )?)?((\\(\\d{1,3}\\))|\\d{1,3})[- .]?\\d{3,4}[- .]?\\d{4}$",
message = "Неверный формат номера!")
@Column(name = "COMPANY_BRANCH_PHONE_NUMBER", unique = true)
private String phoneNumber;
}
Department:
@Entity
@Table(name = "DEPARTMENT")
@Getter
@Setter
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotNull
@NotBlank(message = "Название отдела не может быть пустым!")
@Column(name = "DEPARTMENT_NAME")
private String departmentName;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "LAST_MODIFIED")
private Date lastModified;
@NotNull
@NotBlank(message = "Номер телефона не должен быть пустым")
@Pattern(regexp = "^(\\+\\d{1,3}( )?)?((\\(\\d{1,3}\\))|\\d{1,3})[- .]?\\d{3,4}[- .]?\\d{4}$",
message = "Неверный формат номера!")
@Column(name = "DEPARTMENT_PHONE_NUMBER", unique = true)
private String phoneNumber;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "COMPANY_BRANCH_ID", nullable = false)
private CompanyBranch companyBranch;
@PrePersist
@PreUpdate
protected void setDefaultLastModified(){
lastModified = new Date();
}
}
Employee:
@Entity
@Table(name = "EMPLOYEE")
@Getter
@Setter
public class Employee {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Embedded
private Name name;
@Pattern(regexp = "^(\\+\\d{1,3}( )?)?((\\(\\d{1,3}\\))|\\d{1,3})[- .]?\\d{3,4}[- .]?\\d{4}$",
message = "Неверный формат номера!")
@NotNull
@NotBlank(message = "Телефон не может быть пустым!")
@Column(unique = true, name = "PHONE_NUMBER")
private String phoneNumber;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city",
column = @Column(name = "HOME_CITY")),
@AttributeOverride(name = "zipCode",
column = @Column(name = "HOME_ZIP_CODE")),
@AttributeOverride(name = "street",
column = @Column(name = "HOME_STREET")),
@AttributeOverride(name = "country",
column = @Column(name = "HOME_COUNTRY"))
})
private Address homeAddress;
@Email(message = "Неверный формат почты!")
@NotNull
@Column(unique = true, name = "EMAIL")
private String email;
@Temporal(value = TemporalType.DATE)
@Column(name = "EMPLOYMENT_DATE", updatable = false)
@CreationTimestamp
private Date employmentDate;
@BatchSize(size = 4)
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "EMPLOYEE_STATUS_ID")
private EmployeeStatus employeeStatus;
@NotNull
@Convert(
converter = MoneyConverter.class
)
@Column(name = "SALARY", length = 63)
private Money salary;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "DEPARTMENT_ID")
private Department department;
}
When i am removing department, i want to also change status of each employee in this department, i wanted to do this with @PreRemove
annotation, but I think it is not the best way to do so since EmployeeStatus is an entity class, so I need to inject spring logic inside the entity class. So this is the way I managed the problem:
@Modifying(clearAutomatically = true, flushAutomatically = true)
@Query(value = "UPDATE Employee e SET e.employeeStatus = " +
"(SELECT es FROM EmployeeStatus es WHERE es.employeeStatus = 'FIRED'), " +
"e.department = null " +
"WHERE e.department = :department")
void updateEmployeesStatusToFiredOnDelete(Department department);
And here is method in Department service:
@Transactional
public void deleteDepartment(Department department) {
if (department == null)
throw new IllegalArgumentException("Illegal department for removal!");
departmentRepository.updateEmployeesStatusToFiredOnDelete(department);
departmentRepository.delete(department);
}
But when I am removing company branch, I want also remove all departments inside it and employees statuses should be changed. As I already said, I dont think that @PreRemove
can help me with this. I am thinking about creating a new @Query
for company branch repository, but I think it is too inconvinient. Maybe there are some other solutions for solving this problem? Maybe I still can use @PreRemove
here somehow?
Department deletion and employee status change
In my opinion, you should perform these operations in a single transaction using @Transactional. That is, as you suggested. When an error arises when deleting a deparment, the transaction should be rolled back.
Removing company branch and departments
I don't think so that @PreRemove is the best option. I would simply in one transaction remove the company branch, all departments from company branch and change the employee status using Repository and Spring Data. I think this is a more readable solution.