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.
Related
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.
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.
I was reading a blog regarding bulk fetching with hibernate http://java.dzone.com/articles/bulk-fetching-hibernate.
In this, ScrollableResults is used as a solution. Here still we need to evict objects from session.
I don't understand how using ScrollableResults(or scroll()) is different from using list().
In other words, how the below statements differ in terms of performance
List<Employee> empList = session.createCriteria(Employee.class).list();
ScrollableResults sc = session.createCriteria(Employee.class).scroll();
Please let me know.
The above code seems to be missing some settings.
Query query = session.createQuery(query);
query.setReadOnly(true);
// MIN_VALUE gives hint to JDBC driver to stream results
query.setFetchSize(Integer.MIN_VALUE);
ScrollableResults results = query.scroll(ScrollMode.FORWARD_ONLY);
// iterate over results
while (results.next()) {
Object row = results.get();
// process row then release reference
// you may need to flush() as well
}
results.close();
Follow this link for more details and explanation.
I referred Hibernate API documentation to understand the difference between list() and scroll().
ScrollableResults is like a cursor . An important feature of ScrollableResults is that it allows accessing ith object in the current row of results, without initializing any other results in the row through get(int i) function.
It also allows moving back and forth the result set using next() and previous() function.
Example :
ScrollableResults sc = session.createQuery("select e.employeeName,e.employeeDept FROM Employee e").scroll(ScrollMode.SCROLL_INSENSITIVE);
while(sc.next()) {
String empName = (String)sc.get(0);
System.out.println(empName);
String empdept = (String)sc.get(1);
System.out.println(empdept);
}
The output of above programm will values of employeeName and employeeDept .
Now suppose you want to get the last record of the resultSet. With list() you would need to iterate the whole result. With ScrollableResults, you can use last() function.
Note that for ScrollableResults sc = session.createCriteria(Employee.class).scroll(); should be iterated as
while(sc.next()) {
Employee emp = (Employee)sc.get(0);
System.out.println(emp.getname);
}
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?
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