When I want to create a query using spring-data I follow the above algorithm.
1) Is the query already provided by the existing interfaces of spring-data like CrudRepository
, PagingAndSortingRepository
, JpaRepository
etc?
Examples: saveAndFlush
or findAll
methods, more in docs.
Product product = new Product();
// Setters..
productRepository.saveAndFlush();
2) Can I create a method using keywords inside method names?
Examples: count, more in docs.
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
Long countByTitle(String title);
List<Product> findByTitleLikeAndVisible(String title, boolean visible);
}
3) Can I create a custom query method writing JPQL?
Examples: docs.
In this case spring data does not try to create the query using keywords inside method names, so the method names can be whatever you wish.
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer> {
@Query("SELECT COUNT(p) FROM Product p WHERE p.title=?1")
Long countByTitle(String title);
@Query("SELECT p FROM Product p WHERE p.title LIKE :title AND visible=true")
List<Product> findByTitleLikeAndVisibleTrue(@Param("title") String title);
}
4) Do I want variable column names or variable where conditions? Then the solution is the Specification.
Example: docs, so answer
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer>, JpaSpecificationExecutor<Product> {
}
@Service
public class ProductService {
@Autowired
private ProductRepository productRepository;
public List<Product> findByColumn(String columnName, Object value) {
return productRepository.find((Root<Product> root, CriteriaQuery<?> query, CriteriaBuilder builder) -> {
return builder.and(builder.equal(root.<String>get(columnName), value));
});
}
}
5) Do I want more? The solution is to get the EntityManager and use it like I used it without the spring data library. (This is the answer to this so question)
Example: so answer, more in docs
// Create an interface and add the methods you wish to use with EntityManger.
public interface ProductRepositoryExt {
public List<Product> findByTitle(String title);
}
// Implement the interface you created. Be careful the class name must be identical to the spring-data @Repository interface with the "Impl" appended.
public class ProductRepositoryImpl implements ProductRepositoryExt {
@PersistenceContext
private EntityManager em;
@Override
public List<Product> findByTitle(String title) {
// em.getTransaction().begin();
String sql = "SELECT p FROM Product p WHERE p.title=:title')";
TypedQuery<ProductCategory> query = em.createQuery(sql, Product.class);
query.setParameter("title", title);
// Add the query hints you wish..
query.setHint(org.eclipse.persistence.config.QueryHints.BATCH_TYPE, "JOIN");
query.setHint(org.eclipse.persistence.config.QueryHints.BATCH, "p.productCategory");
return query.getResultList();
// em.getTransaction().commit();
}
}
// Extend this interface from your spring-data @Repository interface.
@Repository
public interface ProductRepository extends JpaRepository<Product, Integer>, ProductCategoryRepositoryExt {
}