Replies: 10 comments 20 replies
-
Any thoughts? |
Beta Was this translation helpful? Give feedback.
-
Great! I can see there is some interest. So far we have 3 variants of implementation. Right off the bat, I like the way Jakarta Data adopted the features of Spring Repository, however, Thank you guys for the feedback! |
Beta Was this translation helpful? Give feedback.
-
[Comment deleted] - I mistakenly thought I was commenting in a Jakarta Data issue and later realized this is under Persistence. Sorry for any confusion that this caused. |
Beta Was this translation helpful? Give feedback.
-
Thank you guys once again for the feedback! I have updated the first post in this discussion to better explain the problem and "tighten up" the problem space. Both Hibernate However, I believe neither of these are "in scope" for this particular discussion. I believe that current Criteria API is currently good enough for this proposal, Although All that needs to be done is to add the |
Beta Was this translation helpful? Give feedback.
-
The |
Beta Was this translation helpful? Give feedback.
-
I hope there is a solution similar to CriteriaDefinition but adopt QueryDSL and jOOQ syntax. For example, CriteriaDSL dsl = new CrieriaDSL(Connection/emf/em, ....)
dsl.select(Book_.TITLE,....)
.from(Book_.leftJoin(Author_))
.where()
.orderBy()
.fetch/fechOne
//reactive version
Flux.from(
dsl.select(Book_.TITLE,....)
.from(Book_.leftJoin(Author_))
.where()
.orderBy() // it is also a Reactive Streams `Publisher`
)
.flatMap/map...
... This is not related to this topic. |
Beta Was this translation helpful? Give feedback.
-
Ok, here is a simpler example. It's somewhat contrived, and actually not a complete representation of the typical workload, Current API: @Inject
EntityManager em;
public List<User> getUsersByFirstName(String firstName, boolean isDescendingOrder,
double startPercentage, int pageSize) {
var criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Long> cq = criteriaBuilder.createQuery(Long.class);
Root<User> rt = cq.from(User.class);
cq.select(criteriaBuilder.count(rt));
cq.where(criteriaBuilder.equal(rt.get("firstName"), firstName));
TypedQuery<Long> q = em.createQuery(cq);
long count = q.getSingleResult();
int firstElement = Long.valueOf(q.getSingleResult() * new BigDecimal(startPercentage / 100).longValueExact())
.intValue();
CriteriaQuery<User> userQuery = criteriaBuilder.createQuery(User.class);
userQuery.select(userQuery.from(User.class));
userQuery.where(criteriaBuilder.equal(rt.get("firstName"), firstElement));
if (isDescendingOrder) {
userQuery.orderBy(criteriaBuilder.desc(rt.get("firstName")));
}
var query = em.createQuery(userQuery).setFirstResult(firstElement)
.setMaxResults(Long.valueOf(Math.max(count, firstElement + pageSize)).intValue());
return query.getResultList();
} With new API: @Inject
JPAFinder<User> em;
public List<User> getUsersByFirstName(String firstName, boolean isDescendingOrder,
double startPercentage, int pageSize) {
QueryEnhancement<User> enhancement = (partial, criteria) -> criteria
.where(partial.builder().equal(partial.root().get("firstName"), firstName));
QueryEnhancement<User> orderBy = (partial, criteria) -> criteria
.orderBy(partial.builder().desc(partial.root().get("firstName")));
long count = em.count(enhancement::accept);
long firstElement = count * new BigDecimal(startPercentage / 100).longValueExact();
return em.findRange(firstElement, Math.max(count, firstElement + pageSize),
isDescendingOrder ?
enhancement.andThen(orderBy)::accept : enhancement::accept).getResultList();
} |
Beta Was this translation helpful? Give feedback.
-
As another pointer to real-world use cases. We (OmniFaces) also took a shot at this a while ago. See https://github.com/omnifaces/optimusfaces |
Beta Was this translation helpful? Give feedback.
-
Having to sit on this for a while, here is my summary so far.
Cons:
Cons: |
Beta Was this translation helpful? Give feedback.
-
@gavinking Here is an idea: Use I believe that would provide the best-of-both worlds solution. |
Beta Was this translation helpful? Give feedback.
-
Problem:
There is no easy, generic way to customize and compose criteria API queries in more of a functional way.
Implementation using the current Criteria API is doable, but not easy or intuitive.
This is typically an issue with things like pagination, infinite scroll and partial data retrieval in general
Solution overview:
I propose to add
findAll()
,findRange()
andcount()
methods toEntityManager
that take lambdas that customize queries on-the-fly.This way, existing APIs can be used in a much more streamlined way with minimal changes.
The parameter can be a record
(Count)QueryCriteria
in the proposed APISolution constraints:
findAll()
,findRange()
andcount()
should be able to take the exact same lambda instance parameter to avoid code duplication for the clientExample real-world use case:
JPALazyDataModel
for PrimeFaces in an integration between JPA and paginated or infinite scrolling data table UI that's implemented in Jakarta Faces. It need to dynamically filter and sort data depending on user input.Documentation for the use case is here: https://docs.flowlogix.com/#section-jpa-lazymodel
Some relevant code links:
Lazy Data Model:
https://github.com/flowlogix/flowlogix/blob/924d3fd39af9eff3935a60ad5de07fc392364940/jakarta-ee/flowlogix-datamodel/src/main/java/com/flowlogix/jeedao/primefaces/internal/JPAModelImpl.java#L199
https://github.com/flowlogix/flowlogix/blob/924d3fd39af9eff3935a60ad5de07fc392364940/jakarta-ee/flowlogix-datamodel/src/main/java/com/flowlogix/jeedao/primefaces/internal/JPAModelImpl.java#L203
JPAFinder Interface - API:
https://github.com/flowlogix/flowlogix/blob/924d3fd39af9eff3935a60ad5de07fc392364940/jakarta-ee/flowlogix-jee/src/main/java/com/flowlogix/jeedao/DaoHelper.java#L75
Current implementation:
This is implemented currently in https://docs.flowlogix.com/#section-jpafinder
Latest iteration of API is here: https://github.com/flowlogix/flowlogix/blob/main/jakarta-ee/flowlogix-jee/src/main/java/com/flowlogix/api/dao/JPAFinder.java
findAll()
/findRange()
/count()
methods could be added toEntityManager
and supporting interfaces (Query*
) can live in another API class fileQuestions:
Where is the best place for this? in JPA or Jakarta Data? Both? (since static metamodel is different?)
Do new
findAll()
/findRange()
/count()
methods belong in EntityManager or somewhere else?Does Criteria API itself need any updates?
What parameter should they take? There are multiple candidates, including Spring, Hibernate, FlowLogix, or Micronaut
Does this duplicate something that already exist or in-progress? (I've looked)
Any other feedback?
Beta Was this translation helpful? Give feedback.
All reactions