Case Insensitive search in hibernate - java

I want to perform a hibernate named query but its giving hibernate syntax exception. In SQL it's running properly..chart will come as a query parameter and query value = 'chart'?
SELECT * FROM faq WHERE UPPER(answer) LIKE UPPER('%chart%')
select f from Faq f where lower(f.question) like lower('%:query%') or lower(f.answer) like lower('%:query%')
#NamedQuery(name = "findQuesAnsByQuery", query = "select f from Faq f where lower(f.question) like lower('%:query%') or lower(f.answer) like lower('%:query%')")
Trace:
[0] = {java.lang.StackTraceElement#16677}"org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:679)"
[1] = {java.lang.StackTraceElement#16678}"org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)"
[2] = {java.lang.StackTraceElement#16679}"org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:411)"
[3] = {java.lang.StackTraceElement#16680}"org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)"
[4] = {java.lang.StackTraceElement#16681}"org.springframework.orm.hibernate3.HibernateTemplate.findByNamedQuery(HibernateTemplate.java:979)"
[5] = {java.lang.StackTraceElement#16682}"org.springframework.orm.hibernate3.HibernateTemplate.findByNamedQuery(HibernateTemplate.java:971)"
[6] = {java.lang.StackTraceElement#16683}"com.hk.impl.dao.BaseDaoImpl.findByNamedQuery(BaseDaoImpl.java:157)"

I think your problem is in using the '%:query%'.. in the query.. Change to this:
#NamedQuery(name = "findQuesAnsByQuery"
, query = "select f from Faq f
where lower(f.question) like lower(CONCAT('%', :query, '%'))
or lower(f.answer) like lower(CONCAT('%', :query, '%'))")
or
#NamedQuery(name = "findQuesAnsByQuery"
, query = "select f from Faq f
where lower(f.question) like lower(:query)
or lower(f.answer) like lower(:query)")
and then set the param:
.setString("query", "%" + query+ "%")

Related

Problem with translating SQL 'IN' subquery into a JPA Criteria Query

I'm trying to translate this SQL query into a JPA Criteria Query:
select distinct student0_.name
from vnic03.student student0_
where (exists(select teacher0_.social_number
from vnic03.teacher teacher0_
where teacher0.social_number = ?
and teacher0_.school_id in (select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id)))
These are the tables (I have simplified and renamed them for posting them here, in reallity they have several million entries):
Right now I have following code:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<String> searchQuery = criteriaBuilder.createQuery(String.class);
Root<Student> root = searchQuery.from(Student.class);
List<Predicate> restrictions = new ArrayList<>();
Subquery<Teacher> subQuery = searchQuery.subquery(Teacher.class);
Root<Teacher> fromSchoolSubQuery = subQuery.from(Teacher.class);
List<Predicate> subRestrictions = new ArrayList<>();
Subquery<School> subQuery2 = searchQuery.subquery(School.class);
Root<School> fromSchoolSubSubQuery = subQuery2.from(School.class);
List<Predicate> subSubRestrictions = new ArrayList<>();
subRestrictions.add(criteriaBuilder.equal(fromSchoolSubQuery.get(Social_number), userInput));
subRestrictions.add(criteriaBuilder.equal(fromSchoolSubQuery.get(School_ID), subQuery2.select(fromSchoolSubSubQuery.get(School_ID)).where(criteriaBuilder.equal(fromSchoolSubSubQuery.get(Student_ID), root.get(student_ID)))));
restrictions.add(criteriaBuilder.exists(subQuery.select(
fromSchoolSubQuery.get(Social_number)).where(
subRestrictions.toArray(new Predicate[0]))));
searchQuery.distinct(true)
.select(root.get(name))
.where( restrictions.toArray(new Predicate[restrictions.size()]) );
TypedQuery<String> query = em.createQuery(searchQuery)
List<String> nameList = query.getResultList();
But this translates into:
select distinct student0_.name
from vnic03.student student0_
where (exists(select teacher0_.social_number
from vnic03.teacher teacher0_
where teacher0.social_number = ?
and teacher0_.school_id = (select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id)))
So I just need to replace the = by in in the last and part. I found in other SO questions something like this:
CriteriaBuilder.In<String> in = criteriaBuilder.in( ??? );
or
Path<Object> path = root.get(student_ID);
CriteriaBuilder.In<Object> in = criteriaBuilder.in(path);
but I just don't know how to use it properly...
So if you know how to translate only this part, it would solve it for me probably already:
where teacher0_.school_id **in** (select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id)))
I found a Solution after reading chapter 5 in this article: https://www.baeldung.com/jpa-criteria-api-in-expressions
Subquery<School> subQueryForInExpression = searchQuery.subquery(School.class);
Root<School> fromSchoolSubQuery = subQueryForInExpression.from(School.class);
subQueryForInExpression.select(fromSchoolSubQuery.get(student_id)).where(criteriaBuilder.equal(fromSchoolSubQuery.get(school_id), root.get(student_id)));
The subQueryForInExpression represents the Select subquery in the IN Expression:
select school0_.id
from vnic03.school school0_
where school0_.student_id = student0_.id
Now we have to add the in Expression to the subRestrictions, this is done with CriterisBuilder.in(...).value(subQueryForInExpression):
subRestrictions.add(criteriaBuilder.in(fromSchoolSubQuery.get(school_id)).value(subQueryForInExpression));

HQL Multiple selects in the select clause

I would like to get in a single query the result of multiple counts. In a native query I can do that like:
`select (select count(*) from Foo where status = 1), (select count(*) from Foo where status = 2) ...`
If I do like that in HQL:
select (select count(f) from Foo f where f.status = 1), (select count(f) from Foo f where f.status = 2)
I get an error:
<AST>:0:0: unexpected end of subtree
How can I do that in HQL?
Your first select is incomplete if you complete it it should be fine.
select (select count(f) from Foo f where f.status = 1), (select count(f) from Foo f where f.status = 2) from Foo;

How to effectively write named queries JPA

I have named queries which looks like the following:
#NamedQueries({
#NamedQuery(name = "table.getvalues", query = "select p from table p where p.a = :a and p.b = :b and p.c = :c order by id"),
#NamedQuery(name = "table.getvalueswhencisnull", query = "select p from table p where p.a = :a and p.b = :b and p.c is null order by id")
})
The only difference between 2 named queries is the the value of the c,c can be null and the syntax of the sql query differs only because of that.
Is there a way where I can club both the statements effectively?
use this :
select p from table p where p.a = :a and p.b = :b and (p.c is null or p.c=:c) order by id
Maybe this filter does a conditional selection.
...AND (p.c=:c OR (:c IS NULL and p.c IS NULL))...

Subquery in where clause with CriteriaQuery

Can anybody give me some hints on how to put that kind of subquery in a CriteriaQuery? (I'm using JPA 2.0 - Hibernate 4.x)
SELECT a, b, c FROM tableA WHERE a = (SELECT d FROM tableB WHERE tableB.id = 3) - the second select will always get a single result or null.
Try something like the following example to create a subquery:
CriteriaQuery<Object[]> cq = cb.createQuery(Object[].class);
Root tableA = cq.from(TableA.class);
Subquery<String> sq = cq.subquery(TableB.class);
Root tableB = cq.from(TableB.class);
sq.select(tableB.get("d"));
sq.where(cb.equal(tableB.get("id"), 3));
cq.multiselect(
cb.get("a"),
cb.get("b"),
cb.get("c"));
cq.where(cb.equal(tableA.get("a"), sq));
List<Object[]> = em.createQuery(cq).getResultList();
Note the code has not been tested due to the lack of an IDE nearby.
You can use DetachedCriteria to represend the sub-query. Your code should look something like:
DetachedCriteria subCriteria = DetachedCriteria.forClass(TableB.class);
subCriteria.add(Property.forName("id").eq(3)); //WHERE tableB.id = 3
subCriteria.setProjection(Projections.property("d")); // SELECT d from
DetachedCriteria criteria = DetachedCriteria.forClass(getPersistentClass());
criteria.add(Property.forName("a").eq(subCriteria)); //a = (sub-query)
criteria.setProjection(Projections.property("a"); //SELECT a
criteria.setProjection(Projections.property("b"); //SELECT b
criteria.setProjection(Projections.property("c"); //SELECT c
return getHibernateTemplate().findByCriteria(criteria);

How can I execute an update (named query) in Hibernate Template?

I have a namedQuery like this:
#NamedQueries ({ ...
#NamedQuery(name = "myUpdate", query = "update User set country = 'EN' where user.id = :id")
...
})
In dao layer
getHibernateTemplate().bulkUpdate(...?)
UPDATE
Query query = sessionFactory.getCurrentSession.getNamedQuery("myUpdate");
getHibernateTemplate.bulkUpdate(query.getQueryString(), id);
I get an error:
Hibernate: update User, set country=EN where id = 2343 ORA-00971: missing SET keyword
Anybody now how can resolve this problem?
UPDATE 2
#NamedQuery(name = "myUpdate", query =
"update User set country = 'EN' where
user.profile.id = ?")
OK
#NamedQuery(name = "myUpdate", query =
"update User set country = 'EN' where
user.profile.name = ?")
NOT OK :(
Unfortunately, that feature is missing in spring, as the named queries are supposed to be used only to retrieve data. One thing you can do is (this is a bit of a work around)
Session session = getHibernateTemplate().getSession();
Query query = session.getNamedQuery("myUpdate");
String update = query.getQueryString();
getHibernateTemplate().bulkUpdate(update, [params]);
I would put that in some kind of helper, so your DAO logic doesn't have to go around spring too.
edit
there's a dangling comma between User and set "update User , set country=EN where"
Actually this is a very old question but I had the same problem today. I realized that the update does not work since you cannont have a join inside of a simple UPDATE. That is also the reason why the comma is added. Hibernate tries to rewrite the query like this:
UPDATE User u, Profile p SET u.country = 'EN' where p.name = ? AND p.id = u.profile.id
To solve the issue you need to select the ids from the second table yourself.
#NamedQuery(name = "myUpdate", query = ""
+ " UPDATE User u "
+ " SET country = 'EN' "
+ " WHERE u.profile.id IN ( "
+ " SELECT p.id "
+ " FROM Profile p "
+ " WHERE p.name = ? "
+ " )"

Categories

Resources