24 Temmuz 2021 Cumartesi

QueryDSL Kütüphanesi

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);
  }
  ...
}

@Repository
public class AuthorRepositoryImpl extends BaseRepositoryImpl<Author, Long>
implements AuthorRepository {
  public AuthorRepositoryImpl(EntityManager em) {
    super(Author.class, em);
  }

  @Override
  public 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; // generated
  final QItem item = QItem.item;                 // generated
  return (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
@Override
public 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.

select metodu
Örnek
Elimizde şöyle bir kod olsun
@Data
@AllArgsConstructor
public class AuthorStatistic {
  private String authorName;
  private Long bookSize;
}
Şöyle yaparız
@Override
public List<AuthorStatistic> findAuthorStatistic() {
  return queryFactory
    .from(author)
    .innerJoin(author.books, book)
    .groupBy(author.fullName)
    .select(Projections.constructor(AuthorStatistic.class,
                        author.fullName,
                        book.count())
    )
    .fetch();
}
Örnek
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