devonfw-forge / devonfw-microservices

Apache License 2.0
2 stars 7 forks source link

spring-data-jpa on quarkus and native queries #45

Closed hohwille closed 3 years ago

hohwille commented 3 years ago

As discussed in #37 with spring-data-jpa we do not have support for native queries inside quarkus.

From real life projects (even with quarkus) we have the feedback that native queries are also an important feature. As the OCX team told me they have it in all of their quarkus apps it must be supported by JPA/Hibernate in quarkus. If for some reason it is not (yet) supported by spring-data-jpa in quarkus we should clarify:

Side node for the second bullet: The Fragment-Approach is kind of odd to me as you always need 3 types for one thing (repo interface, fragment interface, fragment implementation). The initial benefit of spring-data-jpa is to have just one thing which is the repository interface. Ideally you should be able to write default methods for custom implementations directly in the repo interface what already works. However, to avoid exposing the EntityManager via the Repository interface we can not access it from default methods in the interface.

Przemek-Majtyka commented 3 years ago

Please add your planning poker estimate with ZenHub @TugbaDalmaz

GuentherJulian commented 3 years ago

Currently, the quarkus-spring-data-jpa extension only supports the value and countQuery attributes via @Query annotation. nativeQuery is not supported and will cause an IllegalArgumentException (see implementation)

[ERROR]         [error]: Build step io.quarkus.spring.data.deployment.SpringDataJPAProcessor#build threw an exception: java.lang.IllegalArgumentException: Attribute nativeQuery of @Query is currently not supported. Offending method is ... of Repository ...

There is an issue about native query support from November 2019 which is still open: https://github.com/quarkusio/quarkus/issues/5348

GuentherJulian commented 3 years ago

Native queries can direcly be implemented by using the EntityManager:

Query query = entityManager.createNativeQuery("SELECT * FROM Product WHERE title = :title", ProductEntity.class);
query.setParameter("title", searchCriteria.getTitle());
List<ProductEntity> products = query.getResultList();

Be sure to use the name of the table in the query if you use createNativeQuery, while you must use the entity name if you use createQuery.


To avoid the fragment approach, we can use a generic repository as used in the devon4j jpa-spring-data module.

public interface GenericRepository<E> {
  ...

  Query newNativeQuery(String query, Class resultClass);
}

public class GenericRepositoryImpl<E> implements GenericRepository<E> {

  @Inject
  EntityManager entityManager;

  ...

  @Override
  public Query newNativeQuery(String query, Class resultClass) {

    return this.entityManager.createNativeQuery(query, resultClass);
  }

}

Then the repository can extend the generic repository and we can use default methods in the repository to implement our query.

public interface ProductRepository extends JpaRepository<ProductEntity, Long>, GenericRepository<ProductEntity> {

  ...

  default Page<ProductEntity> findByTitle(ProductSearchCriteriaDto dto) {

    Query query = newNativeQuery("select * from Product where title = :title", ProductEntity.class);
    query.setParameter("title", dto.getTitle());
    List<ProductEntity> products = query.getResultList();
    return new PageImpl<>(products, PageRequest.of(dto.getPageNumber(), dto.getPageSize()), products.size());
  }
}
GuentherJulian commented 3 years ago

@hohwille is there anything else to do for this issue?

GuentherJulian commented 3 years ago

Will be closed and continued in a new issue in the devon4j repository