Issue
My understanding is that, by default, Hibernate will set the FetchType to lazy, for all relation types.
In my case, I have a bi-directional OneToMany-ManyToOne relationship, as follows:
Parent class:
public class Parent{
@Id
@Column(name = "parent_id")
private long parentId;
@OneToMany(mappedBy = "parent")
@JsonIgnore
private List<Child> children;
public List<Child> getChildren()
{
return this.children;
}
}
Child class:
public class Child
{
private String name;
@ManyToOne(optional = false) //every child must have a parent
@JoinColumn(name = "parent_id")
private Parent parent;
public Child(Parent parent, String name)
{
this.parent = parent;
this.name = name;
}
}
Child service:
public class ChildService
{
public List<Child> getChildren(long parentId)
{
Parent parent = getParentRepository().findOne(parentId);
return parent.getChildren(); //This returns null
}
public Child getNamedChild(long parentId)
{
Parent parent = getParentRepository().findOne(parentId);
//???????????????
//Not sure how to get the children of this specific parent,
//which has a specific name.
}
}
Parent repository:
public interface ParentRepository extends JpaRepository<Parent, Long> {
}
I have two problems here:
When I call the method getChildren() in ChildService, it returns null. The database does contain the right data. I will need to get these with LAZY fetch type. I have tried to invoke a "parent.getChildren().size()" method, before returning, but it still returns null.
The other problem is how do I get a child that has a specific name? Is it possible to do it via the Repository? Or do I need to getChildren(parentId), and iterate until I find the one that is named in a specific way?
EDIT: After some suggestions, I went on and implemented my ChildRepository this way:
public interface ChildRepository extends JpaRepository<Child, Long> {
@Query("SELECT child FROM Parent parent JOIN parent.child AS child WHERE parent.parentId = :parentId")
List<Child> getChildren(@Param("parentId") String parentId);
@Query("SELECT child FROM Parent parent JOIN arent.child AS child WHERE parent.parentId = :parentId AND child.childId = :childId")
Child getChildByName(@Param("childId") Long childId, @Param("parentId") String parentId);
}
Solution
Can you inject the EntityManager in the ChildService class? I cannot fully verify the code below, but you could try something like
public class ChildService
{
private EntityManager em;
public List<Child> getChildren(long parentId)
{
Query query = em.createQuery("SELECT c FROM Parent p JOIN FETCH p.children AS c WHERE p.parentId = :parentId");
query.setParameter("parentId", parentId);
return (List<Child>) q.getResultList();
}
public Child getNamedChild(long parentId, String name)
{
Query query = em.createQuery("SELECT c FROM Parent p JOIN FETCH p.children AS c WHERE p.parentId = :parentId AND c.name = :name");
query.setParameter("parentId", parentId);
query.setParameter("name", name);
return (Child) q.getSingleResult();
}
}
Answered By - toongeorges