Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA/Hibernate Join and Fetch single column

Tags:

hibernate

jpa

I'm new to JPA/Hibernate. Suppose I have these two tables:

  • Employee (Id, Name, DeptId, ..) // DeptId is foreign key.
  • Department (Id, DeptName, ..) // Department persisted separately

and Entities like below:

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String name;
    private long salary;

    @OneToOne(cascade = {CascadeType.PERSIST})
    @JoinColumn(name="DEPT_ID") 
    private Dept dept;
    ...
    }

@Entity
public class Dept {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String name;
    ...
    **other huge collections with eager fetch ***
    }

In my application DAO, whenever I access the Employee entity, I just need the department name as part of the employee entity and nothing else from the department table.

  1. How to fetch the dept. name column ONLY and not the entire Department row in the employee entity (need to avoid eager fetches for huge collections made by department)? if so, what annotations should I use?
  2. How to handle cascade in this scenario?
like image 267
Ngun Avatar asked Sep 07 '12 01:09

Ngun


1 Answers

The best option is to make the collection lazy loaded and then change the queries where the collection is needed to eager load (using join fetch). If you have a very good reason not to do that then you can try the following workarounds.

You can use a projection query. This will result in a [employee,name] array for each result.

select employee, employee.dept.name from Employee employee

You can use @Formula to map an attribute in Employee table to a column in Department table (note that this solution is Hibernate-specific)

class Employee {

   @Formula("(select deptName from Department where Department.id = DEPT_ID)"
   String deptName;

} 

The other option is to create an new class DeptLite which doesn't have the collection. Map it as readonly - @org.hibernate.annotations.Entity(mutable=false).

@Entity
public class Employee {

    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private int id;
    private String name;
    private long salary;

    @OneToOne(cascade = {CascadeType.PERSIST})
    @JoinColumn(name="DEPT_ID") 
    private Dept dept;

    @OneToOne(updatable=false,insertable=false)
    @JoinColumn(name="DEPT_ID") 
    private DeptLite deptLite;

    ...
}

@Entity
@org.hibernate.annotations.Entity(mutable=false)
class DeptLite  {

}
like image 128
gkamal Avatar answered Sep 17 '22 14:09

gkamal