So let's say I have an ArrayList full of Products that need to be committed to the database via Hibernate. There are already a large number of Products in the database. Each product has an ID. Note this is NOT the PK that is autogenerated by Hibernate.
My questions is: what is the best way to detect conflicts with this ID? I am looking for a relatively efficient method of obtaining, from the the database, a List of Products that share an ID with any of the Products in my ArrayList. This is all in a single table called Products and the ID attribute is in column ProductID.
The way I've done it is grabbing a list of all Products in the database, and compared each one with each entry in my ArrayList - but that is seriously inefficient and I don't think it would work well with a larger database. How should it be done? Thanks. I say "relatively" efficient because efficiency is not the primary concern, but it shouldn't take noticeably long to test against a table of ~1000-5000 rows. Help?
EDIT* I'm very new to hibernate and below is the best I've come up with. How does this look?
for(long id : idList){ //idList just holds the IDs of each Product in my ArrayList
Query query = session.createQuery("select product from Product product where product.id = :id");
query.setLong("id", id);
for(int i = 0; i < query.list().size(); i++){
listOfConflictingProducts.add((Product) query.list().get(i));
}
}
I would call query.list() only once: otherwise the query could be rerun each time:
for(long id : idList){ //idList just holds the IDs of each Product in my ArrayList
Query query = session.createQuery("select product from Product product where product.id = :id");
query.setLong("id", id);
List result = query.list();
for(int i = 0; i < result.size(); i++){
listOfConflictingProducts.add((Product) result.get(i));
}
}
Or, more simply:
for(long id : idList){ //idList just holds the IDs of each Product in my ArrayList
Query query = session.createQuery("select product from Product product where product.id = :id");
query.setLong("id", id);
for(Object obj: query.list()){
listOfConflictingProducts.add((Product)obj);
}
}
Related
I want to know if I can perform em.remove for each element in that local list? Does this code changes state in DB?
TypedQuery<Product> query = em.createNamedQuery("Product.findByCode", Product.class);
query.setParameter("code", code);
List<Product> productList= query.getResultList();
for (int i = 1; i < productList.size(); i++) {
em.remove(productList.get(i));
}
Yes it changes the DB, since that is his job.
The EntityManager API is used to create and remove persistent entity instances, to find entities by their primary key, and to query over entities.
https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html
Using Hibernate Criteria i am trying to achieve pagination but the problem is that for every page fetch i have to make two db calls one for results and another for total records count.
Is there any efficient way so that in a single db call i can get both the data or i can reduce db calls.
Criteria criteria=session.createCriteria(Student.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.add(Restrictions.ne("enquiryStatus", ENQUIRY.JOINED));
criteria.setMaxResults(10);
criteria.setFirstResult((paginate.getStartIndex()-1)*10);
criteria.setProjection(Projections.rowCount());
//here i need to fetch total row count and records
Yes you need the separate query to get the total result count.
Query aCountQuery = session.createQuery("select count(s.id) from Student s
where s.enquiryStatus != :enquiryStatus");
aCountQuery.setParameter("enquiryStatus", ENQUIRY.JOINED);
Long resultCount = (Long)aCountQuery.uniqueResult();
or
Criteria criteria=session.createCriteria(Student.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.add(Restrictions.ne("enquiryStatus", ENQUIRY.JOINED));
criteria.setProjection(Projections.rowCount())
Long resultCount = (Long)criteria.uniqueResult();
Update
Now you can use same Criteria for results with pagination and result count
Criteria criteria=session.createCriteria(Student.class);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
criteria.add(Restrictions.ne("enquiryStatus", ENQUIRY.JOINED));
criteria.setMaxResults(10);
criteria.setFirstResult((paginate.getStartIndex()-1)*10);
List<Student> students = criteria.list();
criteria.setProjection(null);
criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
Long resultCount = (Long)criteria.uniqueResult();
As far As I know there is no direct method to do so.As simple as you can do is write a small hql query(my choice) ,Along with your main criteria.
Number count = (Number) session.createQuery(
"select count(s.id) from Student s").uniqueResult();
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 know that the following code will delete the record with id = 5 from database:
Query query = session.createQuery("delete from Class where id = 5");
query.executeUpdate();
But before i delete it, need to save this record's data in a variable.
So I want to select id = 5, and after some code, I delete it.
It's not efficient if i use two distinct query for them. Because in this way we search database for this item two times.
query = session.createQuery("from Class where id = 5");
//somecode
query = session.createQuery("delete Class where id = 5");
...
So i need a more efficient way to do this, and do it better.
No need to create query to delete a record.
query = session.createQuery("from Class where id = 5");
List list=query.list();
if(list.size()!=0)
{
ClassName obj = (ClassName)list.get(0);
session.delete(obj);
}
Hibernate has a Session.delete() method. Use it if you already have a reference to the entity to remove. No need for a query.
This would also apply the potential cascades configured on associations, which a delete query does not.
Is there any possibility to fetch a collection of an entity just for the retrievement of the size of it?
Something like:
FROM Cat c JOIN SIZE c.kittens
So I can use the result of a query like:
int sum = 0;
for(Cat c : em.createQuery("..", Cat.class).getResultList())
sum += c.getKittens().size();
Is there any keyword or other possibility to get only the size.
It is not a big problem to fetch the whole collection for that purpose but I was just thinking of performance improvements and asked myself how this could be done?
You can use SQL aggregate functions in JPQL
for single Cat
select count(*) from Kittens k where k.cat = :cat
For every Cat at once (all rows in Kittens table)
select count(*) from Kittens k
and retrieve it as
Long size = (Long) query.getSingleResult();