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

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

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.

HIBERNATE: How to convert a Criteria.list() to a "Criteria.map()"

I've a method that retrieves some data from a table and return it in a java.util.List, I need to call that method many times so I'd like to call it just once and put all the data in a java.util.Map, how can I do this?
My method is actually like to:
private List<?> getAll(final Class objClass, final Integer parentId) {
Session session = sessionFactory.getCurrentSession();
Criteria criteria = session.createCriteria(objClass);
if (parentId != null) {
criteria.add(Restrictions.eq("tab.parent", parentId));
}
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
return (List<?>) criteria.list();
}
How can I get a HashMap like HashMap<parentId,List<?>>?
Thanks
As per stackoverflow answer
I don't think this is possible, cause a query always returns a List:
http://docs.jboss.org/hibernate/orm/3.2/api/org/hibernate/Criteria.html#list()
or in a special case a single element.
There is just no method that could return a map.
So without hacks like overwriting the Session to create a special
Criteria which also has a map() method you can't do what you want.
Just return a list and convert it into a map.

Hibernate Criteria Optimization

I was going through the old code in one of our application and found the below scenario.
public <T> List<T> getList(boolean isTrue,String name,String empid)
{
Criteria criteria = session.createCriteria(myType);
criteria.add(Expression.eq("name",name)) ;
if(isTrue&&empid!=null){
criteria.add(Expression.eq("id",empid)) ;
}
List<T> result = criteria.list();
return list;
}
Also the function is called two times like below.
List<T> employeeList = getList(true,name,empId);
if(employeeList.size()==0)
employeeList = getList(false,name,null);
The reason behind this scenario is that sometimes the employeeId won't be correct. In that case we need to do a search only on employee name.
My doubts.
1) If am executing it this way am I querying the database twice ?
2) If yes then is there any way I can optimize it ?
In this case Hibernate will execute the query twice since the parameters are differents.
You can configure query cache and second level cache to improve the performance.
The query cache will return the employeeIds and the second level cache will return the Employee data.

JPA Query.getResultList() - use in a generic way

I'm creating a complex query with multiple tables and need to list the result. Usually, I'm using the EntityManager and map the result to the JPA-Representation:
UserEntity user = em.find(UserEntity.class, "5");
Then I can access all values as the user UserEntity class defines it. But how can I access the field-values returned from a native, multiple-table query? What I get is a List of Objects. That's fine so far, but what "is" that Object? Array? Map? Collection? ...
//simpleExample
Query query = em.createNativeQuery("SELECT u.name,s.something FROM user u, someTable s WHERE s.user_id = u.id");
List list = query.getResultList();
//do sth. with the list, for example access "something" for every result row.
I guess the answer is quite simple, but most examples out there just show the usage when directly casting to a targetClass.
PS: In the example I could use the class-mappings of course. But in my case someTable is not managed by JPA, and therefore I don't have the entity nor do I have a class-representation of it, and since I'm joining like 20 tables, I don't want to create all the classes just to access the values.
General rule is the following:
If select contains single expression and it's an entity, then result is that entity
If select contains single expression and it's a primitive, then result is that primitive
If select contains multiple expressions, then result is Object[] containing the corresponding primitives/entities
So, in your case list is a List<Object[]>.
Since JPA 2.0 a TypedQuery can be used:
TypedQuery<SimpleEntity> q =
em.createQuery("select t from SimpleEntity t", SimpleEntity.class);
List<SimpleEntity> listOfSimpleEntities = q.getResultList();
for (SimpleEntity entity : listOfSimpleEntities) {
// do something useful with entity;
}
If you need a more convenient way to access the results, it's possible to transform the result of an arbitrarily complex SQL query to a Java class with minimal hassle:
Query query = em.createNativeQuery("select 42 as age, 'Bob' as name from dual",
MyTest.class);
MyTest myTest = (MyTest) query.getResultList().get(0);
assertEquals("Bob", myTest.name);
The class needs to be declared an #Entity, which means you must ensure it has an unique #Id.
#Entity
class MyTest {
#Id String name;
int age;
}
The above query returns the list of Object[]. So if you want to get the u.name and s.something from the list then you need to iterate and cast that values for the corresponding classes.
I had the same problem and a simple solution that I found was:
List<Object[]> results = query.getResultList();
for (Object[] result: results) {
SomeClass something = (SomeClass)result[1];
something.doSomething;
}
I know this is defenitly not the most elegant solution nor is it best practice but it works, at least for me.
Here is the sample on what worked for me. I think that put method is needed in entity class to map sql columns to java class attributes.
//simpleExample
Query query = em.createNativeQuery(
"SELECT u.name,s.something FROM user u, someTable s WHERE s.user_id = u.id",
NameSomething.class);
List list = (List<NameSomething.class>) query.getResultList();
Entity class:
#Entity
public class NameSomething {
#Id
private String name;
private String something;
// getters/setters
/**
* Generic put method to map JPA native Query to this object.
*
* #param column
* #param value
*/
public void put(Object column, Object value) {
if (((String) column).equals("name")) {
setName(String) value);
} else if (((String) column).equals("something")) {
setSomething((String) value);
}
}
}
What if you create a bean with all required properties and cast the result using Java 8+ streams?
Like this:
public class Something {
private String name;
private String something;
// getters and setters
}
And then:
import javax.persistence.Query;
...
Query query = em.createNativeQuery("SELECT u.name,s.something FROM user u, someTable s WHERE s.user_id = u.id", Something.class);
List<?> list = query.getResultList();
return list
.stream()
.map(item -> item instanceof Something ? (Something) item : null)
.collect(Collectors.toList());
That way, you don't need to return List<Object[]> nor hide the warning with #SuppressWarnings("unchecked")
Ps.:
1 - I know that this post is very old. But... I'm here in 2021, so others will be coming here too =)
2 - This is wrong or bad practice? Let me know :D
You can also update your hibernate to a version greater than 5.4.30.final

How to avoid hibernate default order by id?

I make this query:
String query = FROM Account acc WHERE acc.id = ? OR acc.id = ? or acc.id = ?...
I have array of ids:
long[] accountIds= {327913,327652,327910,330511,330643};
Then I make
getHibernateTemplate().find(query, accountIds);
I see that the list of accounts I get back from this query is:
327652,327910,327913,330511,330643, obviously , ordered by id.
Any chance I get it back in the order I wrote the ids?
Will appreciate all the help
You may want to use Criteria and its addOrder.
Something like this:
DetachedCriteria cr = DetachedCriteria.forClass(entityClass);
//Add expressions or restrictions to your citeria
//And add your ordering
cr.addOrder(Order.asc("yourID"));
List<T> ls = getHibernateTemplate().findByCriteria(cr);
return ls;
You can't do it on query level.
You can sort after loading from db, something like this
long[] accountIds= {327913,327652,327910,330511,330643};
List<Account> afterHql = getHibernateTemplate().find(query, accountIds);
List<Account> sortedList = new ArrayList<Acount>();
for (long id : accountIds)
{
for (Account account : afterHql)
{
if (account.getId() == id)
{
sortedList.add(account);
}
}
}
It is not possible to fetch results by providing any entity in OR Query or Restrictions.in(). As by deafult when you fire this kind of query it will search for the results id wise. So it will give you results id wise only. You can change the order by using Criteria either in asc or desc. And if you want to have results as per you enter id, then second answer is the only option.
You can only order by column values returned by the query, in a sequence defined by the data type . Wouldn't it be better to pre-order the IDs you supply, and order the query result by ID, so they come out in the same order?

Categories