Currently I use a lot of queries which use constructors for building value objects in JPQL as below
@Query("SELECT new com.DocDTO(d.documentId, d.docType) FROM Document d where d.parentId=:parentId")
Set<DocDTO> getDocsWithinFolder(@Param("parentId") Long parentId);
But as code gets complex, I have a need to build objects with various combinations of constructor parameters, leading to the classic telescoping problem.
As explained in Effective Java (Item1)
is there a way to build a JPQL query by passing a factory method instead of a constructor ? I am thinking something along the lines of
@Query("SELECT DocDTO.query1(d.documentId, d.docType) FROM Document d where d.parentId=:parentId")
Set<DocDTO> getDocsWithinFolder(@Param("parentId") Long parentId);
and then build the appropriate static factory method query1 inside the DocDTO class. Is this possible in JPQL ?
You can use Dynamic projection
to solve this problem. Dynamic projection let you to change return type of single query dynamically. To better understand this lets take a example of this User entity:
@Entity
public class User {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;
private String firstName;
private String lastName;
private String email;
// setter and getters
}
If you want to get only name of a user using dynamic projection first you will need to create a interface like this:
public interface Name {
String getLastName();
String getFirstName();
}
In your repository you will need to create query like this:
<T> List<T> findByLastName(String lastName, Class<T> type);
or with @Query
@Query("select u.firstName,u.lastName from User u where lastName=?1")
<T> List<T> findByLastName(String lastName,Class<T> type);
In your service:
List<Name> name = findByLastName("xyz",Name.class);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With