Are criteria builder faster than named query? - java

I have two tables that looks like:
Table_0
ID Description
5 description5
6 description6
7 description7
8 description8
Table_1
ID Table_0_ID Status
1 5 LOADED
2 6 LOADED
3 7 LOADED
4 7 LOADED
Table_2
ID Table_1_ID
1 1
2 2
3 3
4 4
my expected result when I invoke findAll query is that it eliminates duplicates so result will return (for both tables) three rows (table_1 id from 1 to 3).
I wrote both named query and criteria builder query but the last one seems to be by 4 times faster. I wonder why. Am I making a mistake?
Here is the code:
query = "SELECT OBJECT(sb) FROM Table_2 sb WHERE sb.Table_1.id IN (SELECT MAX(maxsr.id) FROM Table_1 maxsr WHERE maxsr.status = LOADED GROUP BY maxsr.Table_0.id)")
criteria builder:
final EntityManager em = getEntityManager();
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<Table_2> criteriaQuery = cb.createQuery(Table_2.class);
final Root<Table_2> root = criteriaQuery.from(Table_2.class);
Predicate p = getPredicateOnList(data, cb, root, gateSession);
if (p != null) {
criteriaQuery.where(p);
}
final Query q = getEntityManager().createQuery(criteriaQuery);
return q.getResultList();
}
method getPredicateOnList
private Predicate getPredicateOnList(final PaginationData data, final CriteriaBuilder cb, final Root<Table_2> root) {
final Join<Table_2, Table_1> readingJoin = root.join("Table_1");
boolean filterUnloaded = false;
boolean selectMax = true;
for (KeyValuePair pair : data.getRequestParams()) {
if (pair.getKey().equalsIgnoreCase("filterUnloaded")) {
filterUnloaded = ParsingUtils.parseBoolean(pair.getValue(), false);
}
if (pair.getKey().equalsIgnoreCase("selectMax")) {
selectMax = ParsingUtils.parseBoolean(pair.getValue(), true);
}
}
Predicate predicate = null;
if (selectMax) {
List<Long> maxReadingIds = getMaxReadingIds(gateSession.getId(), filterUnloaded);
if (maxReadingIds == null || maxReadingIds.isEmpty()) {
//do nothing
} else {
predicate = readingJoin.get("id").in(maxReadingIds);
}
}
return predicate;
}
method getMaxReadingIds
private List<Long> getMaxReadingIds(Long sessionId, boolean filterUnloaded) {
final CriteriaBuilder cb = em.getCriteriaBuilder();
final CriteriaQuery<Long> maxReadingIdQuery = cb.createQuery(Long.class);
final Root<Table_1> Table_1Root = maxReadingIdQuery.from(Table_1.class);
final Path<Long> idGet = Table_1Root.get("id");
maxReadingIdQuery.select(cb.greatest(idGet));
final Join<Table_1, Table_0> join = Table_1Root.join("Table_0");
maxReadingIdQuery.groupBy(join.get("id"));
Predicate predicate = null;
if (filterUnloaded) {
predicate = cb.equal(Table_1Root.get("status"), LOADED);
}
//omiss sessionId parameter
if (predicate != null) {
maxReadingIdQuery.where(predicate);
}
final Query q = getEntityManager().createQuery(maxReadingIdQuery);
return q.getResultList();
}
(I made some semplification, if code is not well defined please tell me and I supply more information)
Both results are correct but criteria builder is faster.

Related

Why am I getting multiple duplicate criteria results for an ID if it has a one-to-many mapped table with multiple data

I have a parent Entity called CustomerDetailsEntity. It has following one to many mapping to another Entity IBPSDiscrepancyFieldsEntity.
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinColumn(name = "Customer_discrepancy_fk", referencedColumnName = "customer_detail_id")
private Set<IBPSDiscrepancyFieldsEntity> ibpsDiscrepancyFieldsEntity;
Now, say for id=123, in IBPSDiscrepancyFieldsEntity Table, I have 4 rows of data.
Now when I hit criteria search on CustomerDetailsEntity I am getting 4 results with same data instead of one. This is how my search criteria is written:
public Map<String, Object> search(Long slrId, String param, String ibpsStatus, Pageable pageable) {
Criteria criteria = getSession().createCriteria(CustomerDetailsEntity.class);
criteria.add(Restrictions.eq("slrDtlId.sellerDtlId", slrId));
criteria.addOrder(Order.desc("modifiedOn"));
if (param != null && !param.isEmpty()) {
Criterion fName = Restrictions.like("customerFirstName", param+"%");
Criterion lName = Restrictions.like("customerLastName", param+"%");
Criterion appNo = Restrictions.like("loanAppNumber", "%"+param+"%");
Disjunction orExp = Restrictions.or(fName, lName, appNo);
criteria.add(orExp);
}
if (ibpsStatus != null && !ibpsStatus.isEmpty()) {
if (ibpsStatus.equalsIgnoreCase(Constant.IBPS_DISCREPANT)) {
criteria.add(Restrictions.eq("ibpsStatus", IBPSStatus.IBPS_DISCREPANT));
} else if (ibpsStatus.equalsIgnoreCase(Constant.IBPS_RESOLVED)) {
criteria.add(Restrictions.eq("ibpsStatus", IBPSStatus.IBPS_RESOLVED));
}
} else {
Criterion discrepant = Restrictions.eq("ibpsStatus", IBPSStatus.IBPS_DISCREPANT);
Criterion resolved = Restrictions.eq("ibpsStatus", IBPSStatus.IBPS_RESOLVED);
LogicalExpression orExp = Restrictions.or(discrepant, resolved);
criteria.add(orExp);
}
criteria.setFirstResult(pageable.getPageSize() * pageable.getPageNumber());
criteria.setMaxResults(pageable.getPageSize());
List<CustomerDetailsEntity> result = (List<CustomerDetailsEntity>) criteria.list();
Map<String,Object> countResultMap = new HashMap<>(2);
countResultMap.put(Constant.QUERY_RESULT, result);
logger.info("##### checking here");
logger.info("--->"+result.size());
criteria.setFirstResult(0);
Long count = (Long) criteria.setProjection(Projections.rowCount()).uniqueResult();
logger.info("Total Count : "+count);
countResultMap.put(Constant.TOTAL_COUNT, count);
return countResultMap;
}
How do I get only 1 result of CustomerDetailsEntity id=123 when I search, instead of 4 duplicate values. In the logs, result.size() shows as 4. Is the Issue with my mapping or criteria method? Please help.

Return list in alphabetical order using Hibernate

I have a function that returns a list of templates(unsorted); can someone tell me how I can get the list in a sorted format?
public List<FormTemplate> listDomainTemplates(Integer id) {
Domain domain = domainService.getDomain(id);
if (domain == null) {
return new ArrayList<>();
}
CriteriaBuilder cb = sessionFactory.getCurrentSession().getCriteriaBuilder();
CriteriaQuery<FormTemplate> query = cb.createQuery(FormTemplate.class);
Root<FormTemplate> application = query.from(FormTemplate.class);
query.select(application);
Predicate predicate = cb.equal(application.get("domain"), domain);
query.where(predicate);
Query<FormTemplate> q = sessionFactory.getCurrentSession().createQuery(query);
return q.getResultList();
}
Please experiment with following:
query.orderBy(cb.asc(application.get(...));
... - should point to FormTemplate field to sort, I suppose.

Query for multiple tables using JPA Criteria API

I have to make a query in criteria api of two tables that is to say I want to select in the query all the fields of the two tables.
Here I leave the models that I want to select (I have the metamodels of each of them) and I give you an example of how to select the data
of each of them in different consultations
public List<Empleado> empleadoB() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Empleado> criteria = cb.createQuery(Empleado.class);
Root<Empleado> member = criteria.from(Empleado.class);
criteria.select(member).orderBy(cb.asc(member.get(Empleado_.p_ap)));
return em.createQuery(criteria).getResultList();
}
public List<Empleado2> empleadosNom() {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Empleado2> criteria = cb.createQuery(Empleado2.class);
Root<Empleado> member = criteria.from(Empleado.class);
Root<Tipo_docs> tDoc = criteria.from(Tipo_docs.class);
Root<Estad_civil> eCivil = criteria.from(Estad_civil.class);
Root<Profesiones> prof = criteria.from(Profesiones.class);
Root<Eps> eps = criteria.from(Eps.class);
Root<Pensiones> pens = criteria.from(Pensiones.class);
Root<Usuario> useri = criteria.from(Usuario.class);
Root<Cargos> cargo = criteria.from(Cargos.class);
criteria.select(cb.construct(Empleado2.class, member.get(Empleado_.id_emp),
member.get(Empleado_.p_ap), member.get(Empleado_.s_ap),
member.get(Empleado_.nombre), member.get(Empleado_.tipo_doc),
member.get(Empleado_.numero_doc), member.get(Empleado_.lugar_exp),
member.get(Empleado_.fecha_nac), member.get(Empleado_.lugar_nac),
member.get(Empleado_.estadocivil), member.get(Empleado_.direc),
member.get(Empleado_.tel), member.get(Empleado_.profesion),
cb.selectCase() .when(cb.isNull(member.get(Empleado_.matricula_prof)), "No Registrado") .otherwise(member.get(Empleado_.matricula_prof)),
member.get(Empleado_.mail),member.get(Empleado_.eps),
cb.selectCase() .when(cb.isNull(member.get(Empleado_.pensiones)), (long)0) .otherwise(member.get(Empleado_.pensiones)),
cb.selectCase() .when(cb.isNull(member.get(Empleado_.usu)), "No Existe") .otherwise(member.get(Empleado_.usu)),
tDoc.get(Tipo_docs_.desc_tdoc),
eCivil.get(Estad_civil_.desc_ecivil), prof.get(Profesiones_.nombre_prof),
eps.get(Eps_.nom_eps),
cb.selectCase() .when(cb.isNull(member.get(Empleado_.pensiones)), "No Aplica") .otherwise(pens.get(Pensiones_.nom_pension)),
cargo.get(Cargos_.id_cargo), cargo.get(Cargos_.desc_cargo) ));
criteria.where(cb.and(cb.equal(member.get(Empleado_.tipo_doc), tDoc.get(Tipo_docs_.id_entidad)),
cb.equal(member.get(Empleado_.estadocivil), eCivil.get(Estad_civil_.id_ecivil)),
cb.equal(member.get(Empleado_.profesion), prof.get(Profesiones_.id_prof)),
cb.equal(member.get(Empleado_.eps), eps.get(Eps_.id_eps)),
cb.or(cb.equal(member.get(Empleado_.usu), useri.get(Usuario_.usuario)), cb.isNull(member.get(Empleado_.usu))),
cb.or(cb.equal(member.get(Empleado_.pensiones), pens.get(Pensiones_.id_pension)), cb.isNull(member.get(Empleado_.pensiones))) ));
criteria.distinct(true);
return em.createQuery(criteria).getResultList();
}

Filtering data with CriteriaBuilder to compare enum values with literals not working

I have a java class with a enum field,
org.example.Importacion {
...
#Enumerated(EnumType.STRING)
private EstadoImportacion estadoImportacion;
public static enum EstadoImportacion {
NOT_VALID, IMPORTED, ERROR, VALID
}
}
When I create a Query with CriteriaBuilder and I try to compare the enum values, one from a filter to the criteriabuilder using literals, the final result of the query does not filter the enum values, so if I send org.example.Importacion.EstadoImportacion.ERROR to the iterator method, the rersult will not filter ERROR on the filnal result list.
The companyCod filters ok, so If I send "COMPANY001" as a companyCode, the querybuilder filters the final result.
I would like to know how to compare enums in the query:
public Iterator<Importacion> iterator (
long first,
long count,
String companyCod,
org.example.Importacion.EstadoImportacion estado) {
CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
CriteriaQuery<Importacion> criteria = cb.createQuery(Importacion.class);
Root<Importacion> desembolso = criteria.from(Importacion.class);
criteria.select(desembolso);
Predicate p = cb.conjunction();
if(companyCod != null) {
p = cb.and(p, cb.equal(desembolso.get("codigo"), companyCod));
//This part works fine!
}
if (estado != null) {
Expression<org.example.Importacion.EstadoImportacion> estadoImportacion = null;
if (estado.equals(org.example.Importacion.EstadoImportacion.ERROR)) {
estadoImportacion = cb.literal(org.example.Importacion.EstadoImportacion.ERROR);
}
if (estado.equals(org.example.Importacion.EstadoImportacion.IMPORTED)) {
estadoImportacion = cb.literal(org.example.Importacion.EstadoImportacion.IMPORTED);
}
if (estado.equals(org.example.Importacion.EstadoImportacion.NOT_VALID)) {
estadoImportacion = cb.literal(org.example.Importacion.EstadoImportacion.NOT_VALID);
}
if (estado.equals(org.example.Importacion.EstadoImportacion.VALID)) {
estadoImportacion = cb.literal(org.example.Importacion.EstadoImportacion.VALID);
}
p = cb.and(p, cb.equal(estadoImportacion, cb.literal(estado)));
//Doesn't seems to compare enum values
}
criteria.where(p);
javax.persistence.Query query = em.createQuery(criteria);
query.setMaxResults((int)count + (int)first + 1);
query.setFirstResult((int)first);
List resultList = query.getResultList();
Iterator iterator = (Iterator) resultList.iterator();
LOGGER.info("desembolso size: {}", resultList.size());
return iterator;
}
Your criteria compares a literal with the enum. That's not what you want. You want to compare the Importacion's estadoImportacion with the given estado:
Predicate p = cb.conjunction();
if(companyCod != null) {
p = cb.and(p, cb.equal(desembolso.get("codigo"), companyCod));
}
if (estado != null) {
p = cb.and(p, cb.equal(desembolso.get("estadoImportacion"), estado));
}

Adding complicated selections to CriteriaBuilder in EclipseLink?

i want add some more complicated selections as below on date coloumn
select TO_DATE ('04-JAN-2015','DD-MM-YYYY'), to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'FMDAY') day,
(case when to_char(trunc(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'mm'), 'FMDAY') = 'SUNDAY' then to_number(to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'W'))
else ceil((to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'dd') + 1 - to_char(next_day(trunc(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'mm'), 'SUNDAY'), 'dd'))/7)
end)+1 week_no
from dual
here breakupFields is list of string which leads to date column
final QueryBuilder distinctDateTimeFilter = new QueryBuilder() {
final List<String> breakupFields = new ArrayList<String>(fields.length);
for (final String f : fields)
if (!Strings.isEmpty(f)) {
breakupFields.add(f);
}
}
final QueryBuilder distinctDateTimeFilter = new QueryBuilder() {
#Override
public CriteriaQuery buildQuery(CriteriaBuilder cb, CriteriaQuery query, Predicate p, List orders, Root rt) {
Expression selection = null;
selection = cb.function("TO_CHAR", String.class, cb.sum(CriteriaQueryUtils.getPath(rt, breakupFields), cb.literal(miliSecToAdd)),
cb.literal("W-MM-YYYY"));
return query.select(selection).distinct(true).where(p).orderBy(orders);
}
}
final List<Object> objs = new ArrayList<Object>(ds.executeQuery(classObject, Object.class, distinctDateTimeFilter, ef, session,
SuperUserSecurityContext.class));
Can any one suggest how to add
(case when to_char(trunc(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'mm'), 'FMDAY') = 'SUNDAY' then to_number(to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'W'))
else ceil((to_char(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'dd') + 1 - to_char(next_day(trunc(TO_DATE ('04-JAN-2015','DD-MM-YYYY'), 'mm'), 'SUNDAY'), 'dd'))/7)
end)+1 to criteria builder
You can introduce a column in your Entity marked as
#Formula(value="the expression")
See more here and use the column in the queries.
Or you can define native SQL query with the desired entity class mapped and use fuly native SQL.

Categories

Resources