Querydsl
So, in the first section of JPA, I talked mentioned JPQL and queryDSL as an alternative to JPA. Of course, JPA excels in ease of use and removes the necessity for the programmer to write their own query, hastening the entire process of back-end development, but it is:
- Not elastic or specific when creating queries
- Not really necessary because programmers already know how to build queries.
During the beginning phase of the development, I was still new to the concept of JPA and actually felt uneasy at the fact that I couldn’t manipulate the SQL query entirely to my will. Hence, I chose to use queryDSL for the time being and slowly get acquainted to JPA over the course of time. One might argue why I didn’t use only JPQL instead, but I already covered that topic in the previous post: queryDSL’s queries are composed of codes rather than string, making it easier for debugging prior to runtime. Besides, queryDSL is a JPA module that runs atop JPQL, so it’s inevitable that you use it.
Syntax
Prior to using queryDSL, we have to learn the grammar, right? Let’s first look at an example.
1
2
3
Students s = queryFactory.selectFrom(qStudents)
.where(qStudents.firstName.eq("Dolly"))
.fetchOne(); This is a very simple code; one can take a look at it and deduce what it does. Let's try to break the code down, shall we? First, there's the object named queryFactory, which belongs to the JPAQueryFactory class. JPAQueryFactory utilizes the EntityManager to process the query through JPQL, and is a quintessential component for the procedure. The next part is selectFrom(students), which is, as you can tell, equivalent to "SELECT * FROM students". Of course, you can seperate the SELECT and FROM clauses like : "select(s).from(s)", but the former is simply shorter. Inside the where block, you can see the eq method, which is equivalent to "=", and lastly, there's fetchOne(), which means "return one column()". In the case of fetch, one can use fetch() to request for all the corresponding columns in a Collection format. There's a thing called fetchJoin(), which is used to in join clauses, but doesn't per se have the functionality of fetch(); I would like to cover the topic later when I have time.
Okay, let’s look at update now.
1
2
3
4
Long result = queryFactory.update(qStudents)
.where(qStudents.birthPlace.eq("Seoul"))
.set(qStdents.language, "Korean")
.execute();
There are slight alterations here, but nothing major. Firstly, there’s a set block, which is equivalent to “SET …” in SQL query, and also, one can see that fetch() is replaced by execute().
1
2
3
Long result = queryFactory.delete(qStudents)
.where(qStudents.lastName.eq("Johnson"))
.execute(); This is a delete query, and... you get what it's talking about by now.
You might be curious why there isn’t Insert here. The thing is, there’s no Insert statement in queryDSL. Surprising, isn’t it? So, in order to do it, you’ve got to just persist the entity with the EntityManager.
General Process
So, how do I implement queryDSL in my project? How do I set up the environment? You might ask. The first thing you must do is… prepping up for the build. I was using Gradle for building my project, so I added these lines in my build.gradle file.
querydsl-jpa is the queryDSL library, whilst query-apt is used for creating the Q types (Query Types). You may ask, “what is a Q Type?”, but I will get to it in a bit. Also, the import about annotation is required if you want to use queryDSL-related annotations.
The second thing we do is create entity classes for each of the table.
As you can see in the above images. I made multiple entities that correspond to the tables I have in my Database. The objects defined in it should also be identical to the columns of the table. Lastly, annotations like @Getter, @Entity should be used for our own sake; it really shortens up the code.
Then, there are RepositorySupport classes. These classes are subordinate classes related to the Repository class providing queryDSL statements for queries that require specific actions that can be carried out just by using JPA.
In each of the classes, there are methods for specific queries. In which are the Q typed objects. Query type objects are objects that can be used within the JpaQueryFactory’s method. No other objects can be used here. So, how do I make these classes? The thing is, these classes are “generated” upon building the project that has classes with “@Entity” notations and queryDSL annotations.
Troubleshooting
I experienced a problem while importing Q classes. What happened was, one day, when I opened up a project that I had already generated Q classes in, I suddenly couldn’t import the classes even though they were still there.
After searching the internet, there were mainly three solutions. One, we could change the mark on the build folder so that it can be considered a “source folder”. Unfortunately, this created more errors, so I had to revert it back. The second proposed solution was changing the module setting so that build was included upon building. This returned a same result. The third solution was actually what solved my problem; it suggested that I simply clear the cache, run gradle clean, and restart IntelliJ. I followed the instruction, and voila! The problem was solved.
Conclusion
Today we talked about what queryDSL is and how to use it. We also covered topics ranging from basic setup to actual troubleshooting. I am yet to utilize queryDSL’s join functions or any other of its advanced features, so I’m really excited to venture on into this uncharted territory.
Reference
https://www.baeldung.com/intro-to-querydsl
https://velog.io/@cco2416/Querydsl-%EC%82%AC%EC%9A%A9-%EC%A0%95%EB%A6%AC
Comments powered by Disqus.