I have following two JPA entities : Company and Employee which follow one-to-many relationship :
Employee
---------
eId | eName | company_id
Company
--------
cId | cName
I have been trying to fetch Employee IDs list in Company entity. I tried with two ways - employees1 and employees2 as shown below. Both are not working. Note that I want List of Employee IDs and not the List of Employees.
@Entity
public class Employee {
@Id
String eId;
String eName;
}
@Entity
public class Company{
@Id
String cId;
String cName;
// both of the below are not working
@OneToMany(fetch = EAGER, targtEntity = Employee.class )
@JoinColumn(name = "company_id", referencedColumn = "cId")
@Column(name = "eId")
Set<String> employees1 = new HashSet<>();
@OneToMany(fetch = EAGER)
@JoinColumn(name = "company_id", tableName = "Employee", referencedColumn = "cId")
@Column(name = "eId")
Set<String> employees2 = new HashSet<>();
}
For employees1, I am getting : org.hibernate.property.access.spi.PropertyAccessException: Error accessing field.
For employees2 : org.hibernate.cfg.NotYetImplementedException: Collections having FK in secondary table.
Please help!
CodePudding user response:
Check out this article by Vlad Mihalcea, it explains everything in great detail! The optimal mapping would look like this:
@Entity
public class Employee {
@Id
private String eId;
private String eName;
@ManyToOne(fetch = FetchType.LAZY)
private Company refundRequest;
void setRefundRequest(Company refundRequest) {
this.refundRequest = refundRequest;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return Objects.equals(eId, employee.eId);
}
@Override
public int hashCode() {
return Objects.hash(eId);
}
}
@Entity
public class Company {
@Id
private String cId;
private String cName;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "company", orphanRemoval = true)
private List<Employee> employees;
public void addEmployee(final Employee employee) {
employee.setRefundRequest(this);
employees.add(employee);
}
public void removeEmployee(final Employee employee) {
employee.setRefundRequest(null);
employees.remove(employee);
}
}
Make sure to read the above mentioned article to understand why this mapping is optimal!
In order to fetch it, you can use a repository:
@Repository
public interface EmployeeRepository extends JpaRepository<Employee, String> {
@Query("select e.eId from Employee e where e.company = :company")
List<String> findEmployeeIdsByCompany(@Param("company") Company company);
}
By the way, eager fetching is a massive code smell and should be avoided!
CodePudding user response:
@ElementCollection
is the annotation you need to use in this case. @CollectionTable
defines in which table you want to fetch the value from as well as on which column the join happens. @Column
defines the column name you want to fetch from the @CollectionTable
@Entity
class Company {
@Id
String cId;
String cName;
@ElementCollection
@CollectionTable(name = "Employee", joinColumns = @JoinColumn(name = "company_id"))
@Column(name = "eId")
Set<String> employeeIds = new HashSet();
}