Remove rows mappedBy a foreign key of another table - spring-boot

I have two tables Company and Employees. They have a 1-many relation. I want to delete all rows from Company and set null the column with foreign-key from Employees.
#Entity
public class Employees{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int empId;
#ManyToOne
#JoinColumn(name="company_id")
private Company company;
}
#Entity
public class Company{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int comId;
#OneToMany(mappedBy = "company", cascade = CascadeType.ALL)
private List<Employees> employees = new LinkedList<>();
}
public interface CompanyRepository extends JpaRepository<Company, Integer> {
}
public interface EmployeesRepository extends JpaRepository<Employees, Integer> {
}
In controller if I just delete Company rows with #AutowiredCompanyRepository companyRepo; companyRepo.deleteAll(); it shows of course:
Cannot delete or update a parent row: a foreign key constraint fails.
I tried to write an update in EmployeesRepository over Employees to set company.comId to null, because I want to keep the rows, except comId field. In EmployeesRepository I wrote:
#Modifying
#Query("UPDATE Employees e SET e.company.comId=null")
void removeCompanyId();
It caused the following error:
javax.persistence.TransactionRequiredException: Executing an update/delete query

Related

JPA merge table

I have table employee
#Entity
#Table(name = "employee")
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="emp_id")
private Long id;
#Column(name="emp_name")
private String empName;
#Column(name="emp_mail")
private String empMail;
#Column(name="emp_no")
private String empNo;
#Column(name="emp_salary")
private Long empSalary;
#Column(name="type_id")
private Long typeId;
}
In addition, I have table employeetype whose primary key type id is in employee table
How i am able to get response containg type_name not type_id in java data jpa for api using jparepository.
how to join table data.

Is that possible in spring boot that join column (foreign key) with id

I want to join column without object reference. is that possible?
I want to do foreign key without object reference like that
#Data
#Entity
#Table(name = "HRM_EMPLOYEE_SALARY_INCREMENT")
public class EmployeeSalaryIncrement implements Serializable {
private static final long serialVersionUID = 9132875688068247271L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="ID")
private Integer id;
#Column(name = "REFERENCE_NO")
private String referenceNo;
#ManyToOne
#JoinColumn(name = "AUTHORITY", referencedColumnName = "id")
private Integer authority;
#ManyToOne
#JoinColumn(name = "PART_TWO_REGISTER_ID")
private Integer partTwoRegisterId;
#Column(name = "PART_TWO_ORDER_NO")
private String partTwoOrderNo;
#Column(name = "REMARKS")
private String remarks;
#Column(name = "HRM_TYPE")
private Integer hrmType;
}
If I found solve this problem, it will helpful for me.
Joining is not needed in this case. If you only need the foreign key value, then simply add the column as a #Column like any other:
#Data
#Entity
#Table(name = "HRM_EMPLOYEE_SALARY_INCREMENT")
public class EmployeeSalaryIncrement implements Serializable {
private static final long serialVersionUID = 9132875688068247271L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="ID")
private Integer id;
#Column(name = "AUTHORITY")
private Integer authority;
// other fields
// ...
}
No, I don't think that you can join columns between two entities without adding the reference of one to the related entity. You will have to create one entity class corresponding to each of your relational database table and add the reference of one to the other to establish relation.
However, I understand that you may not need all the attributes from your related table based upon your use case, and only wish to select one column from it. You can do that either by only adding required attributes in your joined table entity class (if you are sure you won't need other attributes for that table anywhere else).
Or you can use custom queries using JPQL in your repository class which selects only the required attributes from the tables that you have joined.
I will show you an example of the second way:
//Say, this is your entity class where you wish to join other table to fetch only one attribute from the joined table-
#Entity
#Table(name = "TABLE1", schema = "SCHEMA1")
public class Table1 {
#Id
#Column(name = "ID")
private String id;
#Column(name = "TABLE2_COLUMN")
private String table2Column;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "TABLE2_COLUMN1")
private Table2 table2; //refrence of the joined table entity object
}
// And this is the joined table entity class
#Entity
#Table(name = "TABLE2", schema = "SCHEMA1")
public class Table2 {
#Id
#Column(name = "ID")
private String id;
#Column(name = "TABLE2_COLUMN1")
private String table2Column1;
#Column(name = "TABLE2_COLUMN2")
private String table2Column2; // The column which we want to select from the joined table
}
In your repository class -
#Repository
public interface Table1Repository extends JpaRepository<Table1, String> {
#Query("SELECT t1 FROM Table1 t1 WHERE t1.id = :id")
public List<Table1> getTable1Rows(#Param("id") String id);
#Query("SELECT t1.table2.table2Column2 FROM Table1 t1 WHERE t1.id = :id")
public String getTable2Column2(#Param("id") String id);
}
Based upon the response from Markus Pscheidt below, I agree when he said there's no need to join the entities if you only need the attribute which is a foreign key. As foreign key is already present as an attribute in your entity (or table) you are working with.
If you need to fetch any other column apart from foreign key, then you may use JPQL to fetch the exact column that you wish to select.

Delete object in OneToOne relationship ConstraintViolationException

I'm trying to delete entity which is the owner of the relationship, but I am getting an exception as follows:
org.h2.jdbc.JdbcSQLException: Referential integrity constraint
violation: "FKS59BBPCYQ1GUKBWWA61TYF8YF: PUBLIC.RESERVATIONS FOREIGN
KEY(CAR_LICENSE_ID) REFERENCES PUBLIC.CARS(LICENSE_ID) ('EPA13S')";
SQL statement:
I know that is because of trying to delete an object to which another one has a reference with fk_key. Here is my model:
public class Reservation
{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotNull
#Enumerated(EnumType.STRING)
private DriverType driverType;
private LocalDateTime startTime;
private LocalDateTime stopTime;
#OneToOne(cascade = CascadeType.PERSIST)
private Car car;
private BigDecimal cost;
}
public class Car
{
#Id
#NonNull
#Size(min = 6, max = 6)
String licenseId;
#OneToOne(mappedBy = "car", cascade = CascadeType.REMOVE)
Reservation reservation;
}
How could I possibly deal with such scenario? I would like to delete car from parking when the reservation ends as I don't need it and having license id as pk_key make it vulnerable for trying to insert new car with upcoming reservation even though the previous one has ended.
Deleting car:
carRepository.deleteByLicenseId(reservation.getCarLicenseId());
#Query("DELETE FROM Car c where c.licenseId = :licenseId")
void deleteByLicenseId(#Param("licenseId") String licenseId);
I assume you are extending Spring CrudRepository<Reservation, Long>
The joinColumn is on the Reservation side and from what I can see what you want to do is to delete the Reservation as well. So why not delete it from the owning side, which looks like the reservation.
Change Reservation to.
#OneToOne(cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
Rather use the following for delete.
reservationRepository.delete(reservation);
This is a bidirectional relationship. Add this to Car class:
public void removeReservation() {
if (this.reservation != null) {
this.reservation.setCar(null);
this.reservation = null;
}
}
Call car.removeReservation().
Then delete car.

2 Foreign Keys Into a New Table from Different Entities Hibernate

In my projecet people has role based access.One person can work at more than one departments.
My Role Table
Role_id Role
1 Manager
2 Employee
My Department Table
Departmant_id Departmant
1 Production
2 Research
3 Marketing
My User Table
User_id User_name
1 Jennifer
2 Kate
3 David
What i want is a new table that specifies which people are in which departmant and what role do they have in that department.
User_id Departmant_id Role_id
x x x
What i tried is
Class User{
#ManyToOne(cascade = CascadeType.ALL)
#JoinTable(name = "user_department_role",joinColumns = {#JoinColumn(name = "department_id",referencedColumnName = "department_id"),#JoinColumn(name = "user_id",referencedColumnName = "user_id")}, inverseJoinColumns = {#JoinColumn(name = "role_id")})
private Set<Department> departmentList;
}
You need an association table, often constructed in JPA for various reasons mostly to do with control over what goes in the table or in this case mapping an n-way M:N relationship.
Create all your Entities:
#Entity
public class User {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String userName;
#OneToMany(mappedBy="user")
private Set<UserDepartmentRoleAssociation> associations;
... etc
}
and
#Entity
public class Department {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String department;
#OneToMany(mappedBy="department")
private Set<UserDepartmentRoleAssociation> associations;
... etc
}
and
#Entity
public class Role {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;
private String role;
... etc
}
and create your association table and id class.
#Entity
public class UserDepartmentRoleAssociation {
#EmbeddedId private UserDepartmentRoleAssociationId id;
#ManyToOne #MapsId("userId")
private User user;
#ManyToOne #MapsId("departmentId")
private Department department;
#ManyToOne #MapsId("roleId")
private Role role;
public UserDepartmentRoleAssociation() {
id = new UserDepartmentRoleAssociationId();
}
... etc
}
and
#Embeddable
public class UserDepartmentRoleAssociationId implements Serializable {
private Integer userId;
private Integer departmentId;
private Integer roleId;
... etc
}
and to persist a relationship then ...
User user = new User();
user.setUserName("user1");
Department department = new Department();
department.setDepartment("department 1");
Role role = new Role();
role.setRole("Manager");
UserDepartmentRoleAssociation association = new UserDepartmentRoleAssociation();
association.setUser(user);
association.setDepartment(department);
association.setRole(role);
em.persist(user);
em.persist(department);
em.persist(role);
em.persist(association);
and to read it with join fetch then
User user = em.createQuery("select u from User u left join fetch u.associations ass left join fetch ass.department left join fetch ass.role where u.id = :id", User.class).setParameter("id", 1).getSingleResult();
Note that I have used a Set instead of a List in Department and User which causes much less problems in these cases. Also, I don't have to create associations when I persist the relationship because the UserDepartmentRoleAssociation is the owning entity and therefore does the persisting. The associations sets are created by JPA when it reads a record.

#OneToMany relationship issue while saving multiple values in Hibernate and Spring

I have two entities with #OneToMany bidirectional relationship as below:
#Entity
public class Company {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer companyId;
private String name;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy="company")
Set<Employee> employees = new LinkedHashSet<>();
Employee class
#Entity
public class Employee {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer empId;
private String name;
private String address;
private String email;
#ManyToOne
#JoinColumn(name="companyId")
Company company;
Intially i saved 2 employees as below:
Employee emp= new Employee();
emp.setName("John");
emp.setEmail("John#gmail.com");
employeeRepository.save(emp);
Employee emp2= new Employee();
emp2.setName("Smith");
emp2.setEmail("smith#gmail.com");
employeeRepository.save(emp2);
Now I want to save one employee working for 2 different companies like below:
Company company =new Company();
company.setName("Google");
Employee emp = employeeRepository.findOne(1);
company.getEmployees().add(emp);
emp.setCompany(company);
companyRepository.save(company);
Company company2 =new Company();
company2.setName("Microsoft");
company2.getEmployees().add(emp);
emp.setCompany(company2);
companyRepository.save(company2);
It is updating only second company id into employee table. I want both the companies to be assigned to that employee. How can I do that?
The issue here is that you have a one-to-many when obviously it should be a many-to-many, viz. an employee can work for more than one company and a company has many employees.
You can either change the relationship to a #ManyToMany (and use #JoinTable if required) or you can create another entity, say, CompanyEmployee to which both Employee and Company have a one-to-many-relationship. The latter approach is probably preferable as you can then record additional information about the association e.g. start_date, end-date etc.
#Entity
#Table(name = "company_employees")
public class CompanyEmployee {
#ManyToOne
private Employee employee;
#ManyToOne
private Company company;
private Date startDate;
private Date endDate;
}

Resources