I am using Spring boot JPA to below execute below query
select DELTA_TYPE,OPERATION_ID,COUNT(*) from ACTIVE_DISCREPANCIES ad group by DELTA_TYPE,OPERATION_ID
DELTA_TYPE,OPERATION_ID, etc may come from external system, in repository class I tried to execute native query
#Query(value="select OPERATION_ID,DELTA_TYPE,count(*) from ACTIVE_DISCREPANCIES ad group by ?1",nativeQuery = true)
public List<Object[]> groupByQuery(#Param("reconType") String recGroupColumns);
where recGroupColumns="DELTA_TYPE,OPERATION_ID" but didnt work as #param will split ','
Second option for me was criteria query
public List<Object[]> getReconGroupList() {
String recGroupColumns = "OPERATION_ID,DELTA_TYPE";
String[] arrStr = recGroupColumns.split(",");
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Object[]> query = criteriaBuilder.createQuery(Object[].class);
Root<ActiveDiscrepancies> adr = query.from(ActiveDiscrepancies.class);
query.groupBy(adr.get("operationId"), adr.get("deltaType"));
// query.groupBy(adr.get("deltaType"));
query.multiselect(adr.get("operationId"), adr.get("deltaType"), criteriaBuilder.count(adr));
TypedQuery<Object[]> typedQuery = entityManager.createQuery(query);
List<Object[]> resultList = typedQuery.getResultList();
return resultList;
}
Here how can I pass groupBy and multiselect dynamically?
Using projections we can solve this scenario, below is the code
Criteria criteria = getSession().createCriteria(ActiveDiscrepancies.class);
ProjectionList projectionList = Projections.projectionList();
for(String str : colList) {
projectionList.add(Projections.groupProperty(str));
}
projectionList.add(Projections.rowCount());
criteria.setProjection(projectionList);
List results = criteria.list();
getSession().close();
Related
please help me out writing criteria builder for this query
SELECT *
FROM XYZ
WHERE date_v < "2020/01" AND
id NOT IN (SELECT id FROM XYZ WHERE date_v = '2020/01')
i have looked at using subqueries in jpa criteria api but i am unable to figure it
I have tried using subquery and joins but it throwing different error after all i get to know that i need to get more clarity about query criteria usages. any help much appreciated
You have to create XyzEntity with Long id and LocalDate date_v fields.
// query
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<XyzEntity> query = cb.createQuery(XyzEntity.class);
Root<XyzEntity> root = query.from(XyzEntity.class);
LocalDate date = LocalDate.of(2020, 1, 1);
// subquery
Subquery<Long> subQuery = query.subquery(Long.class);
Root<XyzEntity> subRoot = subQuery.from(XyzEntity.class);
Predicate idSubPredicate = cb.equal(root.get("id"), subRoot.get("id"));
Predicate dateSubPredicate = cb.equal(subRoot.get("date_v"), date);
subQuery.select(subRoot.get("id")).where(idSubPredicate, dateSubPredicate);
// query predicates
Predicate datePredicate = cb.greaterThan(root.get("date_v"), date);
Predicate notExistsPredicate = cb.exists(subQuery).not();
// query result
query.select(root).where(datePredicate, notExistsPredicate);
List<XyzEntity> result = entityManager.createQuery(query).getResultList();
I have mentioned the corrections in comments for the answer but I feel providing full solution seems good and helps others:
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Entity> query = cb.createQuery(Entity.class);
Root<Entity> root = query.from(Entity.class);
// subquery
Subquery<Long> subQuery = query.subquery(Long.class);
Root<Entity> subRoot = subQuery.from(Entity.class);
Predicate subPredicate = cb.equal(subRoot.get("date_v"), dateValue);
subQuery.select(subRoot.get("id")).where(subPredicate);
// query predicates
Predicate datePredicate = cb.lessThan(root.get("date_v"), dateValue);
Predicate notExistsPredicate = root.get("id").in(subQuery).not();
// query result
query.select(root).where(datePredicate, notExistsPredicate);
Query d = entityManager.createQuery(query);
List<Entity> resultList = d.getResultList()
I have 2 entities Addemp and Job.I want to join these 2 tables based on empid .empid is foreign key in job table and primary key in addemp table
here i am doing a search operation based on employee id .i am using criteria builder for search operation
the relationship here is manytoone
public List<Object[]> findEmployeeList(Integer id)
{
EntityManager em=null;
try
{
em=getEntityManager();
CriteriaBuilder cb=em.getCriteriaBuilder();
CriteriaQuery cq=cb.createQuery(Addemp.class);
Root<Addemp>rt= cq.from(Addemp.class);
Join<Addemp,Job> job=rt.join(Addemp_.jobCollection);
Predicate predicate=cb.equal(rt.get("empId"),id);
cq.where(predicate);
/* cq.select(rt.get("firstName"));
cq.where (cb.equal(rt.<String>get("empId"),id));*/
Query qry= em.createQuery(cq);
return qry.getResultList();
Based on the question and JPQL query from the above comments here is the criteria query proposal:
public List<Tuple> findEmployeeList(Integer id)
{
em = getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Addemp> empRoot = cq.from(Addemp.class);
Root<Job> jobRoot = cq.from(Job.class);
cq.multiselect(empRoot.get("empId").alias("id"),
empRoot.get("firstName").alias("first"),
empRoot.get("lastName").alias("last"),
jobRoot.get("jobTitle").alias("title"),
jobRoot.get("empStatus").alias("status"),
jobRoot.get("subUnit").alias("subunit"));
cq.where(cb.equal(empRoot.get("empId"), id));
TypedQuery<Tuple> q = em.createQuery(cq);
return q.getResultList();
}
Next you may want to extract a tuple result:
List<Tuple> tuples = service.findEmployeeList(2);
for (Tuple t : tuples) {
StringBuilder builder = new StringBuilder(64)
.append(t.get("id")).append(", ")
.append(t.get("first")).append(", ")
.append(t.get("last")).append(", ")
.append(t.get("title")).append(", ")
.append(t.get("status")).append(", ")
.append(t.get("subunit"));
System.out.println(builder.toString());
}
I hope it helps.
When using the JPA Criteria API, what is the advantage of using a ParameterExpression over a variable directly? E.g. when I wish to search for a customer by name in a String variable, I could write something like
private List<Customer> findCustomer(String name) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class);
Root<Customer> customer = criteriaQuery.from(Customer.class);
criteriaQuery.select(customer).where(cb.equal(customer.get("name"), name));
return em.createQuery(criteriaQuery).getResultList();
}
With parameters this becomes:
private List<Customer> findCustomerWithParam(String name) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Customer> criteriaQuery = cb.createQuery(Customer.class);
Root<Customer> customer = criteriaQuery.from(Customer.class);
ParameterExpression<String> nameParameter = cb.parameter(String.class, "name");
criteriaQuery.select(customer).where(cb.equal(customer.get("name"), nameParameter));
return em.createQuery(criteriaQuery).setParameter("name", name).getResultList();
}
For conciseness I would prefer the first way, especially when the query gets longer with optional parameters. Are there any disadvantages of using parameters like this, like SQL injection?
you can use ParameterExpression like this:
assume that you have some input filter, an example could be this:
in your query you have to check the value of a fiscal Code.
let's start:
first of all create criteriaQuery and criteriaBuilder and root
CriteriaBuilder cb = _em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<RootEntity> soggettoRoot = cq.from(RootEntity.class);
1) inizialize a predicateList(use for where clause) and a paramList(use for param)
Map<ParameterExpression,String> paramList = new HashMap();
List<Predicate> predicateList = new ArrayList<>();
2 )check if the input is null and create predicateList and param
if( input.getFilterCF() != null){
//create ParameterExpression
ParameterExpression<String> cf = cb.parameter(String.class);
//if like clause
predicateList.add(cb.like(root.<String>get("cf"), cf));
paramList.put(cf , input.getFilterCF() + "%");
//if equals clause
//predicateList.add(cb.equal(root.get("cf"), cf));
//paramList.put(cf,input.getFilterCF()());
}
3) create the where clause
cq.where(cb.and(predicateList.toArray(new Predicate[predicateList.size()])));
TypedQuery<Tuple> q = _em.createQuery(cq);
4) set param value
for(Map.Entry<ParameterExpression,String> entry : paramList.entrySet())
{
q.setParameter(entry.getKey(), entry.getValue());
}
When using a parameter, likely (dependent on JPA implementation, datastore in use, and JDBC driver) the SQL will be optimised to a JDBC parameter so if you execute the same thing with a different value of the parameter it uses the same JDBC statement.
SQL injection is always down to the developer as to whether they validate some user input that is being used as a parameter.
I have the following line of code to get the results based on like statement using Hibernate 4 API
Predicate predicate = cb.like(emp.get(EmployeeDetail_.empName),
empName+"%");
The generated sql statement is
select employeede0_.EMPLOYEE_NAME as EMPLOYEE1_0_ from EMPLOYEES employeede0_
where employeede0_.EMPLOYEE_NAME like 'smith%'
How can I modify my java code to have EMPLOYEE_NAME in lower case? The generated sql output should be like the following
select employeede0_.EMPLOYEE_NAME as EMPLOYEE1_0_ from EMPLOYEES employeede0_
where lower(employeede0_.EMPLOYEE_NAME) like lower('smith%')
Complete code for getting results
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Employee> c = cb.createQuery(Employee.class);
Root<Employee> emp = c.from(Employee.class);
c.select(emp);
List<Predicate> criteria = new ArrayList<Predicate>();
ParameterExpression<String> pexp = cb.parameter(String.class,
"empName");
Predicate predicate = cb.like(emp.get(Employee_.empName),
empName+"%");
criteria.add(predicate);
if (criteria.size() == 1) {
c.where(criteria.get(0));
} else if (criteria.size() > 1) {
c.where(cb.and(criteria.toArray(new Predicate[0])));
}
TypedQuery<EmployeeDetail> q = entityManager.createQuery(c);
data.setResult(q.getResultList());
Use CriteriaBuilder#lower():
Predicate predicate = cb.like(cb.lower(emp.get(EmployeeDetail_.empName)),
empName.toLowerCase() + "%");
My named query looks like this, thanks to here.
#NamedQuery(
name="Cat.favourites",
query="select c
from Usercat as uc
inner join uc.cat as c
where uc.isFavourtie = true
and uc.user = :user")
And the call to implement looks like this :
Session session = sessionFactory.getCurrentSession();
Query query = session.getNamedQuery("Cat.favourites");
query.setEntity("user", myCurrentUser);
return query.list();
What would be the equivalent criteria query that returns a list of cats ?
With JPA 2.0 Criteria:
(This is one of the many ways you can achieve this using JPA 2.0 Criteria api)
final CriteriaQuery<Cat> cq = getCriteriaBuilder().createQuery(Cat.class);
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
final Root<Usercat> uc= cq.from(Usercat.class);
cq.select(uc.get("cat");
Predicate p = cb.equal(uc.get("favourtie", true);
p = cb.and(p, cb.equal(uc.get("user"), user));
cq.where(p);
final TypedQuery<Cat> typedQuery = entityManager.createQuery(cq);
return typedQuery.getResultList();