Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Static Factory Method in JPQL query instead of constructor

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 ?

like image 601
HopeKing Avatar asked Oct 16 '22 22:10

HopeKing


1 Answers

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);
like image 53
Ajit Soman Avatar answered Nov 04 '22 00:11

Ajit Soman