Home > Mobile >  Hibernate one-to-many to fetch only primary key column of the target entity
Hibernate one-to-many to fetch only primary key column of the target entity

Time:01-23

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();

}
  • Related