Using native sql in java criteria predicate - java

I have a predicate(javax.persistence.criteria.Predicate) which filters raw data as follows:
public Predicate byAccountsId(Collection<Long> accountsId) {
ParameterExpression<?> param = createParam(AOraArrayUserType.class, new AOraArrayUserType(accountsId));
return criteriaBuilder().or(
criteriaBuilder()
.equal(criteriaBuilder().function("in_ex", Long.class, actSourceJoin().get(Account_.id),
param), 1),
criteriaBuilder().equal(
criteriaBuilder().function("in_ex", Long.class, actDestinationJoin().get(Account_.id),
param), 1));
}
This predicate builds the next part of the query:
..
where
..
act.source_id in (accountsId.values())
or act.destination_id in (accountsId.values() - array ids)
..
It works fine but there may be too much raw data.I want to use "Oracle functional index", which removes unnecessary data from the query results. I tried to rewrite my predicate as follows:
public Predicate byAccountsId(Collection<Long> accountsId) {
ParameterExpression<?> param = createParam(AOraArrayUserType.class, new AOraArrayUserType(accountsId));
return criteriaBuilder().or(
criteriaBuilder().literal(
Restrictions.sqlRestriction("case when state != 'ARCHIVE' then source_id else null end"))
.in(param));
}
Resurlt query builds fine but returns no result. But when I copy result query to sql developer and run the query it returns the expected result.
Part of the query which is build by new predicate:
..
where
..
(case when act.state != 'ARCHIVE' then act.source_id else null end) in (accountsId.values() - array ids)
..
Does anybody know why I don't get the correct result when I'm using the new predicate?
And can I use hibernate.criterion.Restrictions with javax.persistence.criteria.Predicate?

You can define #Formula for the expression in your Entity (AOraArrayUserType) and use the field in criteria
Restrictions.in("theFormulaField", param)

Related

How to do a .filter() in hibernate

In the django orm I can do something like the following:
people = Person.objects.filter(first_name='david')
for person in people:
print person.last_name
How would I do the equivalent in Java Hibernate's orm? So far, I've been able to do a single get, but not a filter clause:
Person p = session.get(Person.class, "david");
What would be the correct way to do this though?
you can use native SQL
session.beginTransaction();
Person p = getSingleResult(session.createNativeQuery("SELECT * FROM People where name = 'david'",Person.class));
session.getTransaction().commit();
and the function getSingleResult would be somthing like this :
public static <T> T getSingleResult(TypedQuery<T> query) {
query.setMaxResults(1);
List<T> list = query.getResultList();
if (list == null || list.isEmpty()) {
return null;
}
return list.get(0);
}
you can get a list like this :
List<Person> list = session
.createNativeQuery("SELECT * FROM People", Person.class)
.getResultList();
There are several approaches to do this so here goes:
Lazy way - possibly bad if you have a tons of data is to just load up
the whole list of persons, stream it and apply a filter to it to
filter out objects not matching the given first name.
Use a HQL query (Hibernate Query Language) to create a select query
https://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/chapters/query/hql/HQL.html
Use Hibernate's Criteria API to achieve the above
https://docs.jboss.org/hibernate/orm/5.3/userguide/html_single/chapters/query/criteria/Criteria.html
Alternatively you can even use a native SQL query to do the above.

How to mock aggregate function result with JOOQ?

I call the count aggregate function in my service class using JOOQ.
SelectQuery<Record> query = this.dsl.selectQuery();
query.addSelect(DSL.count());
query.addFrom(SOME_TABLE);
final Integer total = query.fetchOne(0, Integer.class);
I need to mock count result in my unit test.
What is the best way to do that?
Following jooq documentation, I have to create result record with relevant fields count.
Something like that:
Result<Record1<Integer>> result = create.newResult(...);
But what I have to use as the create.newResult() method parameters in case of creating the mock record for aggregate function?
Your query should return one row with one column, so create that result:
Field<Integer> c = DSL.count();
Result<Record1<Integer>> result = create.newResult(c);
result.add(create.newRecord(c).values(42));
The documentation you've linked shows a very similar example:
...
// You decide, whether any given statement returns results, and how many
else if (sql.toUpperCase().startsWith("SELECT")) {
// Always return one record
Result<Record2<Integer, String>> result = create.newResult(AUTHOR.ID,AUTHOR.LAST_NAME);
result.add(create
.newRecord(AUTHOR.ID, AUTHOR.LAST_NAME)
.values(1, "Orwell"));
mock[0] = new MockResult(1, result);
}
...

How to use Hibernate SQL projection query?

I have a SQL projection query that returns a list, but I want a single result. Here is my projection query:
Criteria criteria = getCurrentSession().createCriteria(TbLoyaltytrans.class)
.add(Restrictions.eq("custid", custId))
.setProjection(Projections.projectionList()
.add(Projections.sum("pointin").as("pointin"))
.add(Projections.sum("pointout").as("pointout"))
.add(Projections.sqlProjection(
"(pointin - pointout) as points",
new String[]{"points"},
new org.hibernate.type.DoubleType[]{
new org.hibernate.type.DoubleType()
}),
"points")
);
I want a single object, i.e.: the count from the above query.
What I did wrong with the above query?
I assume your are using criteria.list() in order to get the list. You can use criteria.uniqueResult() and it will return a single Object or null.

get all the values in where clause for empty stirng using hibernate

i am building a shopping cart using jsp and hibernate.
i am filtering the content by brand size and price using checkboxes
the checked checkboxes are returned to the class where hql query exists.
so i want i single hql query that can handle this.
as like if one of the parameter like size is empty (means user doesnt uses it to filter the content ) than an empty string is passed to the hql query which returns any value...
so is there anything possible that all values can be retrived in where clause for empty string or some other alternative except coding different methods for different parameter...
I typically use the Criteria api for things like this... if the user does not specify a size, do not add it to the criteria query.
Criteria criteria = session.createCriteria(MyClass.class);
if(size != null && !size.isEmpty()){
criteria.add(Restrictions.eq("size", size);
}
To have multiple restrictions via an OR statement, you use Disjunction. For an AND, you use Conjunction.
Criteria criteria = session.createCriteria(MyClass.class);
Disjunction sizeDisjunction = Restrictions.disjunction();
String[] sizes = { "small", "medium", "large" };
for(int i = 0; i < sizes.length; i++){
sizeDisjunction.add(Restrictions.eq("size", sizes[i]);
}
criteria.add(sizeDisjunction );
First, good practices say that instead of passing and empty String to the query, you should pass null instead. That said, this hql should help you:
from Product p
where p.brand = coalesce(:brand, p.brand)
and p.size = coalesce(:size, p.size)
and p.price = coalesce (:price, p.price)

using hibernate Criteria.uniqueResult() when there are several results

I have a table USERS with names and creation dates, and an api function
T read(Criterion... criteria)
that searches by criterions that i cant change.
My problem is that the function returns crit.uniqueResult() but sometimes the criteria gives many names (in which case i want only the name with the latest date).
how can i add a criterion to make sure only the latest name is returned?
public T read(Criterion... criteria){
Criteria crit = getSession(false).createCriteria(this.type);
for (Criterion c : criteria)
{
crit.add(c);
}
T entity = (T)crit.uniqueResult();
return entity;
}
Maybe you can have a read method that returned the top result, a method that returns a List<T> and one that you pass in the number of results to return.
For example you could use then use max results setting
criteria.setMaxResults(1);
List<T> results = criteria.list();
return results.get(0);
http://docs.jboss.org/hibernate/core/3.2/api/org/hibernate/Criteria.html#setMaxResults%28int%29

Categories