I'm trying to create a query using CriteriaBuilder where I need to have a predicate where the value of the predicate is like the value in the database.
Basically, I need to be able to do the following:
WHERE myTestValue LIKE columnValue
In native queries, it is an option to do that, but using the CriteriaBuilder or NamedQueries, it does not seem to work.
String myValue = "foo#bar.com";
cb.where(cb.like(myValue, root.get(Entity_.email));
Is there an option in JPA to do it like this? Or should I fall back to native queries?
EDIT
I need to be able to check if a given value matches a wildcard entry in database. So the database has a record %#bar.com%, and I need to check if my given value foo#bar.com matches to that record.
I think your params should be other way round:
cb.where(cb.like(root.get(Entity_.email),myValue);
Aditionally you may need to use add this to the second param:
cb.where(cb.like(root.get(Entity_.email),"%"+myValue+"%");
Chris found the answer. First I need to "generate" a parameter.
ParameterExpression<String> senderEmailParameter = cb.parameter(String.class, "senderEmailParameter");
Path<String> senderEmailPath = root.get(Entity_.senderEmail);
Predicate predEmail = cb.like(senderEmailParameter, senderEmailPath);
And then I need to fill the parameter in the query.
q.where(predEmail);
return em.createQuery(q).setParameter("senderEmailParameter", senderEmail).getSingleResult();
This works! Thanks Chris!
Related
I am have a problem where i need to join two tables using the LEAST and GREATEST functions, but using JPA CriteriaQuery. Here is the SQL that i am trying to duplicate...
select * from TABLE_A a
inner join TABLE_X x on
(
a.COL_1 = least(x.COL_Y, x.COL_Z)
and
a.COL_2 = greatest(x.COL_Y, x.COL_Z)
);
I have looked at CriteriaBuilder.least(..) and greatest(..), but am having a difficult time trying to understand how to create the Expression<T> to pass to either function.
The simplest way to compare two columns and get the least/greatest value is to use the CASE statement.
In JPQL, the query would look like
select a from EntityA a join a.entityXList x
where a.numValueA=CASE WHEN x.numValueY <= x.numValueZ THEN x.numValueY ELSE x.numValueZ END
and a.numValueB=CASE WHEN x.numValueY >= x.numValueZ THEN x.numValueY ELSE x.numValueZ END
You can code the equivalent using CriteriaBuilder.selectCase() but I've never been a big fan of CriteriaBuilder. If requirements forces you to use CriteriaBuilder then please let me know and I can try to code the equivalent.
CriteriaBuilder least/greatest is meant to get the min/max value of all the entries in one column. Let's say you want to get the Entity that had the alphabetically greatest String name. The code would look like
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery query = cb.createQuery(EntityX.class);
Root<EntityX> root = query.from(EntityX.class);
Subquery<String> maxSubQuery = query.subquery(String.class);
Root<EntityX> fromEntityX = maxSubQuery.from(EntityX.class);
maxSubQuery.select(cb.greatest(fromEntityX.get(EntityX_.nameX)));
query.where(cb.equal(root.get(EntityX_.nameX), maxSubQuery));
I created a sample Spring Data JPA app that demonstrates these JPA examples at
https://github.com/juttayaya/stackoverflow/tree/master/JpaQueryTest
It turns out that CriteriaBuilder does support calling LEAST and GREATEST as non-aggregate functions, and can be accessed by using the CriteriaBuilder.function(..), as shown here:
Predicate greatestPred = cb.equal(pathA.get(TableA_.col2),
cb.function("greatest", String.class,
pathX.get(TableX_.colY), pathX.get(TableX_.colZ)));
I want to make my small spring project effectively. So I use IN clause instead of using loops in hql.
01) Question in setParameterList()
To use setParameterList(), we have to pass list object
List<Department> listDeptmntId = reportService.listDepartmentID(companyId); //list of objects
String hql = "select s.department.departmentName, g.dateTime from Gauge g inner join g.survey s where s.department in (:dpts)";
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setParameterList("dpts",listDeptmntId);
The query works fine. But this return only one (first object in listDeptmntId list) resultset, does not return other results.
I tries to pass integer list like [1,2,3] using following method also not working.
List<Integer> dptIds=listDeptmntId.stream().map((Department::getDepartmentId()).collect(Collectors.toList());
02) Question in setParameter()
int cId=10;
String hql="...... companyId=:id"
Query query = sessionFactory.getCurrentSession().createQuery(hql);
query.setParameter("id",cId);
Sometime when I use parameter passing ("=:") , it does not work for Integers . But directly setting variable to query like following is working
int cId=10;
String hql="...... companyId="+cId
Query query = sessionFactory.getCurrentSession().createQuery(hql);
My code may be wrong because I'm going through ebooks and referring materials to do the project. Thank you in advance.
I generally do IN(?, ..., ?) using an java.sql.Array.
long[] deptIds = listDeptmntId.toArray(new long[listDeptmntId.size()];
java.sql.Array array = conn.createArrayOf("LONG", deptIds);
query.setPameter("depts", array);
q1) Check the join (can't see any other reasons to return just one object). And passing [1,2,3] won't work with that query because in query you're dealing with department object. If you want [1,2,3] to work change the query to check for dept-ids like this -> "select s.department.departmentName, g.dateTime from Gauge g inner join g.survey s where s.department.id in (:id-list)"
q2) You've already created the query object when you set the parameter, so setting parameter at that point might not affect the query object. (Your "+" approach works since the parameter is set to the query when creating the query object.)
I need to optimize a query that iterates over several objects and I wanted Spring Data to let the database handle it. I want to end up with a HashMap<String,String> that looks like
2134_9877, 9877
2134_2344, 2344
3298_9437, 9437
The SQL would be select convert(varchar,b.id)+'_'+convert(varchar,a.id)',a.id from t1 a join t2 b on a.jc = b.jc
So far, I've got Whatever-QL in the repository that looks like:
#Query("SELECT new map (a.bkey, a.akey) FROM mergeTable a WHERE a.discr= ?1")
The problem is, bkey is not unique, it is only unique when paired with akey and the monstrosity that I have to feed it to wants them combined with an underscore: 2345_2177.
I have tried a.bkey.toString and ''+a.bkey and new String(a.bkey) and just string(a.bkey) (that last gives a new exception but still doesn't work) but Spring doesn't like any of these. I can find no questions asking this and it seems I cannot use SQLServer's convert() function as this ain't SQL.
How can I concatenate the Integers as Strings with an underscore in this #Query?
PS: Using the native query that's been debugged in SQLServer throws some weird alias exception in Hibernate so I think 'going native' is predetermined to be a dead end.
If I have understood it right, the 'Whatever-QL' is called JPQL, and the operator CONCAT can be used. Only the use of it, as it accepts two or more parameters depends on the JPA version you are running.
Here is the answer.
JPA concat operator
You could add a getter to your entity like this:
public String getCombinedKey(){
return a.akey + "_" + a.bkey;
}
The advantage is you could handle here null's and other things if you want and it's more reusable in case you need this in another place. If you do it just in the repository you will have to copy it everytime.
Your query would then be:
#Query("SELECT new map (a.combinedKey, a.akey) FROM mergeTable a WHERE a.discr= ?1")
I have an entity kind called Account. One of the fields is a String named selfie, which is basically the url to a selfie uploaded by a user. I want to fetch for users who have a selfie (so if a user does not have a selfie they should not be included in the result set). I have the following query. but it won't work because I have "NULL" as a string. What is the correct way for doing this? Again, I only want users who have selfies.
Filter selfie = new FilterPredicate("selfie", FilterOperator.GREATER_THAN, "NULL");
Query query = new Query(Account.class.getSimpleName()).setFilter(selfie);
FetchOptions options = FetchOptions.Builder.withLimit(30);
DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
QueryResultList<Entity> entities = datastore.prepare(query).asQueryResultList(options);
Also I am open to a JDO/JPA way of doing this on App-Engine (but it must work on App-Engine).
After some trial and error on https://console.cloud.google.com/datastore/entities/query/gql
I found this work around expression for IS NOT NULL:
> NULL
Example:
Select * from State where customer_id > NULL
I haven't tested this on a field with negative values.
This should be as simple as
Filter selfie = new FilterPredicate("selfie", FilterOperator.NOT_EQUAL, null);
where you actually pass the Java null value (not a String) and filter with not equals (see https://stackoverflow.com/a/22200137).
Personally, I've been using JDO for my datastore management, which has its pros and cons. Let me know if you'd like to see a solution using JDO as well. Cheers!
I am new to hibernate and still learning the basics. I'd appreciate if someone can point me in the right direction.
I have a class:
Destination
id
name
longitude
latitude
I can read destinations based on id with something like this:
List result = session.createQuery("from Destination as d where d.id=2").list();
However, I want to read destinations from database using name. I can perhaps write something like this as a query:
String name; // name set somewhere else, say a function argument
List result = session.createQuery("from Destination as d where d.name LIKE %"+name).list();
I believe this will yield all destinations with names similar to (variable) name.
Is there something inbuilt in hibernate for such use cases or is there a better way to handle this ?
EDIT:
One thing that follows from my thought process is: name column on destination db table will have an index setup. Can I map this index in some way to the Destination class using hibernate ?
You could build your query by concatenating strings. A more elegant solution would be to use the Hibernate Criteria API.
You query would then look something like:
List result = session.createCriteria(Destination.class)
.add(Restrictions.like("name", "%" + name)
.list();