Giriş
"Type Safe" SQL cümlesi yazmak için kullanılır. Açıklaması şöyle
QueryDSL is an external library that uses annotation processing to generate additional classes – called Q—types. These are copies of the JPA entities but introduce an API that allows us to create database queries.
Maven
Şu satırı dahil ederiz
<dependency><groupId>com.querydsl</groupId><artifactId>querydsl-jpa</artifactId></dependency><dependency><groupId>com.querydsl</groupId><artifactId>querydsl-apt</artifactId></dependency>
QueryDSL kod ürettiği için şu satırı dahil ederiz. Böylece her bir @Entity sınıfı için QFoo şeklinde kod üretilir.
<plugin><groupId>com.mysema.maven</groupId> <artifactId>apt-maven-plugin</artifactId> <version>1.1.3</version> <executions> <execution> <goals> <goal>process</goal> </goals> <configuration> <outputDirectory>target/generated-sources/java</outputDirectory> <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor> </configuration> </execution> </executions> </plugin>
JPAQuery Sınıfı
select metodu
Örnek
Şöyle yaparız
entityManager.getTransaction().begin(); List<User> users = new JPAQuery<User>(entityManager) .select(QUser.user) .from(QUser.user) .where(QUser.user.email.endsWith("gmail.com") .and(QUser.user.firstName.eq("Alice"))) .orderBy(QUser.user.lastName.asc()) .fetch(); entityManager.getTransaction().commit(); entityManager.close();
JPAQueryFactory Sınıfı
constructor
Şöyle yaparız
@Configuration class QueryDslConfiguration { @PersistenceContext private EntityManager em; @Bean public JPAQueryFactory jpaQueryFactory() { return new JPAQueryFactory(em); } }
fetch metodu
Şöyle yaparız
import com.querydsl.core.types.dsl.BooleanExpression; import com.querydsl.jpa.impl.JPAQuery; import com.querydsl.jpa.impl.JPAQueryFactory; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.support.PageableExecutionUtils; import org.springframework.stereotype.Repository; import org.springframework.util.StringUtils; @Repository @RequiredArgsConstructor public class DefaultTeamQueryRepository { private final JPAQueryFactory queryFactory; public List<MemberResponse> findMembersByTeamId(long teamId) { QMember memberTable = new QMember("member"); return queryFactory .select(new QMemberResponse(memberTable.id,memberTable.name)) .from(memberTable) .where(memberTable.team.id.eq(teamId)) .fetch(); } }
fetchFirst metdou
Şöyle yaparız
public abstract class BaseRepositoryImpl<T, ID> extends SimpleJpaRepository<T, ID>
implements BaseRepository<T, ID> {protected final QAuthor author = QAuthor.author;protected final QBook book = QBook.book;private final EntityManager em;protected final JPAQueryFactory queryFactory;public BaseRepositoryImpl(Class<T> domainClass, EntityManager em) {super(domainClass, em);this.em = em;this.queryFactory = new JPAQueryFactory(em);}...}@Repositorypublic class AuthorRepositoryImpl extends BaseRepositoryImpl<Author, Long>
implements AuthorRepository {public AuthorRepositoryImpl(EntityManager em) {super(Author.class, em);}@Overridepublic Optional<Author> findByEmailIgnoreCase(String email) {return Optional.ofNullable(queryFactory.select(author).from(author).where(author.email.equalsIgnoreCase(email)).fetchFirst());}}
fetchJoin metodu
N+1 Select Problem çözümü için kullanılır. JPQL karşılığı olarak "JOIN FETCH" kullanılır.
Örnek
Şöyle yaparız
import com.querydsl.jpa.impl.JPAQueryFactory;public Shipment getById(final UUID id) {final QShipment shipment = QShipment.shipment; // generatedfinal QItem item = QItem.item; // generatedreturn (Shipment) new JPAQueryFactory(entityManager).from(shipment).innerJoin(shipment.items, item)
.fetchJoin() //Items is lazy, the fetchJoin will load it.where(shipment.id.eq(id.toString())).fetchOne();}
Örnek
Şöyle yaparız
@Overridepublic List<Author> findAllWithBooks() { return queryFactory .select(author) .distinct() .from(author) .innerJoin(author.books, book) .fetchJoin() .fetch(); }
offset metodu
Şöyle yaparız
public Page<MemberResponse> members(Pageable pageable) { QMember memberTable = new QMember("member"); List<MemberResponse> members = queryFactory .select(new QMemberResponse(memberTable.id,memberTable.name)) .from(memberTable) .offset(pageable.getOffset()) .limit(pageable.getPageSize()) .fetch(); return PageableExecutionUtils.getPage(members, pageable, () -> countQuery().fetchOne()); } private JPAQuery<Long> countQuery() { QMember memberTable = new QMember("member"); return queryFactory .select(memberTable.count()) .from(memberTable); } }
Açıklaması şöyle
We can use the same Pageable from Spring Data. Note that PageableExecutionUtils.getPage() is used instead of new PageImpl(...). This is an optimization technique to reduce the number of count calls.
Örnek
Elimizde şöyle bir kod olsun
@Data@AllArgsConstructorpublic class AuthorStatistic {private String authorName;private Long bookSize;}
Şöyle yaparız
Örnek@Overridepublic List<AuthorStatistic> findAuthorStatistic() {return queryFactory.from(author).innerJoin(author.books, book).groupBy(author.fullName).select(Projections.constructor(AuthorStatistic.class,author.fullName,book.count())).fetch();}
Elimizde şöyle bir kod olsun
import com.querydsl.core.annotations.QueryProjection; public record MemberResponse(long id, String name) { @QueryProjection public MemberResponse { } }
Şöyle yaparız
public List<MemberResponse> findMembersByTeamId(long teamId) { QMember memberTable = new QMember("member"); return queryFactory .select(new QMemberResponse(memberTable.id,memberTable.name) .from(memberTable) .where(memberTable.team.id.eq(teamId)) .fetch(); }
Hiç yorum yok:
Yorum Gönder