Hibernate updating bulk persistence entites - java

I am using hibernate in my application to update bulk entries in list.
I have a list of employees which I get from the database by running particular criteria query. As the whole method is under transactional annotation.I want to udpate each employee in this list. So i can update the employee objects in the list, by just calling setter methods on employee objects , there is no need to call update method explicitly, as the whole list objects are under persistent context.
As of now, I am using for loop to iterate the list and updating each employee by calling setter method
like below:
for(Employee emp:empList){
emp.setAge(5);
emp.setAddress("ABC");
}
Now updating like this takes lot of time ,if I have 1000 employees in the list. how can i apply bulk operation when I am updating the fields in the persistent context by setting corresponding setter values and not by calling update method.
Thanks

try this if you are using JPA 2.1.
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaUpdate<Employee> update = cb.createCriteriaUpdate(Employee.class);
Root<Employee> root = update.from(Employee.class);
//Acces properties by metamodel entity
root.set(Employee_.age, 5);
root.set(Employee_.address, "ABC");
//Add conditions where
update.where([...])
Query query = em.createQuery(update);
query.executeUpdate();
Be careful if you perform more write operations in the same method because the bulk operations of criteria do not respect the order of execution of the transaction.

Related

JPA/Hibernate seems to convert a query with an in clause into multiple queries with = clauses

A solution we implemented in order to collect a large amount of heavy objects in reasonable time and without memory overflow (I'm speaking of objects with multiple fetchType.eager relations, to entities that themselves have eager fetched relations), was to first select ids of those objects, and then select the objects themselves based on these ids.
Coming the time to optimise our code, we noticed (using hibernate.show_sql=true) that the query we used to gather those objects (select a from A a where a.id in :ids) is translated by JPA/Hibernate into thousands of queries of the form select a from ...endless join list... where a.id = ?
The question is the following:
Why JPA/Hibernate transforms our initial query with an "in" clause into so many queries with "=" clauses. Isn't it inefficent ? If so, is there a way to prevent that ?
Here's how the query is called in our code:
Query q = this.getContext().createQuery("select a from A a where a.id in :ids");
q.setParameter("ids", idList);
return (List<A>) q.getResultList();
Hi you should use setParameterList instead of setParameter.
Also no need to use select in hibernate if you want to get the complete entity object.
Query q = this.getContext().createQuery("from A a where a.id in (:ids)");
q.setParameterList("ids", idList);
return (List<A>) q.getResultList();
If your idList is more that 1000 elements, you probably hit this Oracle-specific deoptimization https://hibernate.atlassian.net/browse/HHH-9299.
One way to solve this is to break idList into multiple chunks, execute a query for each and concatenate the results.
Though I still can't explain why a query is generated for each ID provided in the in clause (provided in my original question), I found a solution to this problem on this blog (https://thoughts-on-java.org/fetch-multiple-entities-id-hibernate/).
The solution consists in using Hibernate's session API as follows:
//get session object from entity manager
Session session = em.unwrap(Session.
MultiIdentifierLoadAccess<A> multiLoadAccess = session.byMultipleIds(A.class);
List<A> aObjects= multiLoadAccess.withBatchSize(1000).multiLoad(idList);
return aObjects;

Hibernate: how to update element order in a list (order generated by #orderColumn) without fetching the list

I have entity with list of sub entities, and I want to keep the order of the sub entities so I used the annotation #OrderColumn.
#OrderColumn(name = "pos")
private List<Child> children;
now I wish to change position of one child in the list, the way to do that is to fetch the list of child and then change the order in the list, then flush/commit this change.
but I want to do it in the DB with hql/hibernate criteria update statement. (because children list may be a huge list and I don't want to spend time on fetching this)
how can I access my generated field (pos) in hql/hibernate criteria?
is there a way yo do it?

JPA createNativeQuery not mapping to Entity class

I am trying to use createNativeQuery to get a result set from my database and map it to a list of Entity objects.
When i do
List<MyObject> results = this.em.createNativeQuery(query, MyClass.class).getResultList();
I end up with an array of Entity objects that is the correct size, and mapped to the columns correctly, but they are all the same object. The first result returned gets duplicated for every entry in my list.
In the picture above you can see that I get data back, and if i inspect the ovbjects they are mapped to my columns properly. But they are all the same object.
But if i do
List<Object[]> objects = this.em.createNativeQuery(query, Object.class).getResultList();
I get a list of distinct Objects like it should be. But they are not mapped to my Entity class.
In the above pic, you can see that when I use Object and stead of my Entity class type, I get a result set of distinct objects for each row returned. I cannot figure out why when i use my Entity class it just repeats the same row over and over.
Does anyone know what could be causing me to get a list of the same object each time?
My query is selecting from a Pipelined function in a stored procedure
String query = "select * from table(myschema.mypackage.myfunction(input_var))";
UPDATE
The pipelined function I am calling inside my procedure returns about 200 rows. For testing purposes, I have only mapped the first few of the columns.
My Entity class has column mappings for the first 13 of the 200 columns.
My query that calls the function is doing a select *, so, it is returning all 200 columns and mapping the first 13. I thought this was a possible issue, but I just tried it with a new test class I made and doing a select * from a regular table into an Entity that only had 2 of the columns mapped. There was no issue. It returned a list of distinct objects.
My conclusion is that there must be something preventing Hibernate from iterating through the result set of my pipelined function. It returns the correct number of rows, but it gets stuck on the first row and just creates that object over and over.
The issue doesnt seem to have anything to do with my column mappings
Solved it.
Turns out I was just not paying attention and over thinking what I had done.
I had my #Id annotation in my Entity class on a column that turned out was not distinct. When i was checking me work I was only paying attention to the size of the list being returned.
After fixing my #Id on the right column, it is now returning the full list of distinct objects.
Did you trying using something like this?
StoredProcedureQuery q = em.createStoredProcedureQuery("stored_procedure_name");
q.registerStoredProcedureParameter("empList", something.class, ParameterMode.REF_CURSOR);
List<MyObject> myObj= (List<>)q.getOutputParameterValue("paramValue");
// ...
Can you try to provide explicit Result Set mapping
#SqlResultSetMapping(
name="myMapping",
entities={#EntityResult(entityClass=MyClass.class)}
And then
em.createNativeQuery(query, "myMapping").getResultList();

How to speed up eager loading of foreign collections?

I have a database table mapped with ORMlite, it contains some data (18 columns) and it also contains ForeignCollectionField(eager = true).
Problem is when loading all data from this table ... ORMlite is creating query for every item instead using joins. Which is resulting in 67124 queries and taking forever to load all objects from this table.
This could be however done in right join query under few seconds? Why to generate thousands of queries instead?
How can I speed it up? Do I have to write raw query and then RawRowMapper , which makes using ORM pointless..
How to deal with loading eager collections in ormlite? Because queryForAll is not way..
Problem is when loading all data from this table ... ORMlite is creating query for every item instead using joins. Which is resulting in 67124 queries and taking forever to load all objects from this table.
It's ORM_Lite_ for a reason. Lot of people have asked for the join support on foreign collections but I've not gotten to it yet. It's not easy.
If you still want to use ORMLite then I'd recommend not using eager = true and doing 2 queries instead. One query for your main item and then another query using the DAO associated with the collection entity using IN. Something like:
qb = accountDao.queryBuilder();
qb.where()...;
List<Account> accounts = qb.query();
// build a list of account-ids
List<Long> accountIds = new ArrayList<>();
for (Account account : accounts) {
accountIds.add(account.getId());
}
// now use this list of ids to get your other entities
List<Order> orders = orderDao.queryBuilder().where().in("accountId", accountIds).query();
// now you have a list of orders for all of your ids
// you will need to associate each order with its account
Hope this helps.

Does EclipseLink store ordered entity List incorrect?

I have entity named Test1, it has 2 fields id and name.
I put about 1000 entity Test1 into a ArrayList with first entity has id = 1, second entity has id = 2, and so on... to 1000.
I use EclipseLink 2.4 provider to communication Postgresql database.
When I store List into database using following code:
EntityManager em;
List<Test1> list = new ArrayList<Test1>();
//populate data into list
for(Test1 test1 : list){
em.merge(test1);
}
When I check database, the rows is not ordered as expected. The first row does not have id = 1, and the second row does not have id = 2 and so on...
What's wrong with EclipseLink or I got mistake?
From what you wrote, you cannot be sure who is responsible for that: either your DB / DB client (when you check the order), or the EcliplseLink. Anyway, if you want a certain order for your JPA operations, you should use EntityManager.flush() in order to hit the DB, otherwise the persistence provider can decide when and in which order to flush its query cache. Also, if you want a certain order in your client, you should sort the results, as some databases (like MySQL) do not guarantee that the rows are returned in the same order in which they have been inserted.
I think it depends, depends on what?
Depends if the List has been marked with #OrderColumn annotation, default is not store the order of the list, but it depends on your model an eclipselink can be configured to store order and be the responsible for the correct update of that field.
Also use OrderColumn could be a hit in the performance so use with caution

Categories