Following up on a question I posted yesterday: How to populate POJO class from custom Hibernate query?
Can someone show me an example of how to code the following SQ
Writing (exist this type of Challenges working with hibernate)
I am not saying about custom EntityRepository interface which extends JpaRepository on SpringBoot which you can write custom Query with @Query -> here you can't write query with optional params e.g. if param is null don't append it in query string. And you can use Criteria api of hibernate but it not recommended in their documentation because of performance issue...
But exist simple and error prone and performance good way...
Write your own QueryService class which are methods will get string(answer for first and second problem) sql and will map result to Custom class (third problem) with it's any association @OneToMany, @ManyToOne ....
@Service
@Transactional
public class HibernateQueryService {
private final Logger log = LoggerFactory.getLogger(HibernateQueryService.class);
private JpaContext jpaContext;
public HibernateQueryService(JpaContext jpaContext) {
this.jpaContext = jpaContext;
}
public List executeJPANativeQuery(String sql, Class entity){
log.debug("JPANativeQuery executing: "+sql);
EntityManager entityManager = jpaContext.getEntityManagerByManagedType(Article.class);
return entityManager.createNativeQuery(sql, entity).getResultList();
}
/**
* as annotation @Query -> we can construct here hibernate dialect
* supported query and fetch any type of data
* with any association @OneToMany and @ManyToOne.....
*/
public List executeHibernateQuery(String sql, Class entity){
log.debug("HibernateNativeQuery executing: "+sql);
Session session = jpaContext.getEntityManagerByManagedType(Article.class).unwrap(Session.class);
return session.createQuery(sql, entity).getResultList();
}
public List executeGenericHibernateQuery(String sql, Class entity){
log.debug("HibernateNativeQuery executing: "+sql);
Session session = jpaContext.getEntityManagerByManagedType(Article.class).unwrap(Session.class);
return session.createQuery(sql, entity).getResultList();
}
}
Use case - you can write any type condition about query params
@Transactional(readOnly = true)
public List findWithHibernateWay(SearchFiltersVM filter){
Long[] stores = filter.getStores();
Long[] categories = filter.getCategories();
Long[] brands = filter.getBrands();
Long[] articles = filter.getArticles();
Long[] colors = filter.getColors();
String query = "select article from Article article " +
"left join fetch article.attributeOptions " +
"left join fetch article.brand " +
"left join fetch article.stocks stock " +
"left join fetch stock.color " +
"left join fetch stock.images ";
boolean isFirst = true;
if(!isArrayEmptyOrNull(stores)){
query += isFirst ? "where " : "and ";
query += "stock.store.id in ("+ Arrays.stream(stores).map(store -> store.toString()).collect(Collectors.joining(", "))+") ";
isFirst = false;
}
if(!isArrayEmptyOrNull(brands)){
query += isFirst ? "where " : "and ";
query += "article.brand.id in ("+ Arrays.stream(brands).map(store -> store.toString()).collect(Collectors.joining(", "))+") ";
isFirst = false;
}
if(!isArrayEmptyOrNull(articles)){
query += isFirst ? "where " : "and ";
query += "article.id in ("+ Arrays.stream(articles).map(store -> store.toString()).collect(Collectors.joining(", "))+") ";
isFirst = false;
}
if(!isArrayEmptyOrNull(colors)){
query += isFirst ? "where " : "and ";
query += "stock.color.id in ("+ Arrays.stream(colors).map(store -> store.toString()).collect(Collectors.joining(", "))+") ";
}
List articles = hibernateQueryService.executeHibernateQuery(query, Article.class);
/**
* MapStruct [http://mapstruct.org/][1]
*/
return articles.stream().map(articleMapper::toDto).collect(Collectors.toList());
}