How to prevent Hibernate load the whole collection? - java

For example, I have the following entity:
class User{
...
private Set questions;
...
}
When I operate the domain model:
user.questions.add(...);
Hibernate will load ALL the questions of this collection, even if I set the collection to LAZY. How can I change this behavior?

You'll have to annotate the collection with
#LazyCollection(LazyCollectionOption.EXTRA)

TL;DR
Don't do this, load all the collection on request.
Details
I think you should reconsider your desire to avoid loading the collection when its elements are updated via add() method call. Here are my arguments:
When you add element, the result (i.e. whether element added or not) might depend on type of the collection. For Set - it definetely depends on collection contents.
In terms of business logic, your Set represents some questions related to user. Let's imagine you achieved the result you want - first five questions are in the collection, the rest ten are not. What is the business meaning of the collection then? Sounds really questionable.
If you consider my arguments bad, feel free to use the techniques described in other answers.

So actual problem description: when I apply cascading there is a performance issue because there can be many questions.
My answer would then be: then don't use cascading to save questions, persist the question using a regular EntityManager.persist() call.
Pretty obvious, right?

If the resultSet size is very huge you can do it in batches by setting max limits
query.setMaxResults(int maxResults)

Related

Putting all returned elements into a Spring-Boot cache using annotations

Using spring-boot and its caching mechanism, is it possible to automatically store all entities returned as a collection into the cache one by one?
For instance picture the following Repository method:
#Query("...")
List<Foo> findFooByBar(Bar bar);
I'd like to insert these in a Spring Cache, one by one, meaning there would be N insertions (one for each element in the list) rather than just one (the whole list).
Example:
#Query("...")
#CachePut(value = "foos", key = "result.each.id")
List<Foo> findFooByBar(Bar bar);
Sometime ago, another person asked a similar/related question on SO and I provided an answer along with an example.
As you know, by default, out-of-the-box Spring does not handle multiple keys/values in the way that you suggested, though I like your thinking here and your example/UC is valid.
Often times, however, you can achieve what you want using an intermediate solution with just a bit of extra work. Spring is an excellent example of the Open/Closed principle and the 2 primary abstractions in Spring's Cache Abstraction is the Cache and CacheManager interfaces.
Typically, you can pick an existing implementation and "adapt" either the Cache or the CacheManager, or both, as I have done in my example.
Though not as ideal or convenient, hopefully this will give you some ideas until perhaps SPR-15213 is considered (though maybe not).
Cheers,
John

List vs Set on JPA 2 - Pros / Cons / Convenience

I have tried searching on Stack Overflow and at other websites the pros, cons and conveniences about using Sets vs Lists but I really couldn't find a DEFINITE answer for when to use this or that.
From Hibernate's documentation, they state that non-duplicate records should go into Sets and, from there, you should implement your hashCode() and equals() for every single entity that could be wrapped into a Set. But then it comes to the price of convenience and ease of use as there are some articles that recommend the use of business-keys as every entity's id and, from there, hashCode() and equals() could then be perfectly implemented for every situation regardless of the object's state (managed, detached, etc).
It's all fine, all fine... until I come across on lots of situations where the use of Sets are just not doable, such as Ordering (though Hibernate gives you the idea of SortedSet), convenience of collectionObj.get(index), collectionObj.remove(int location || Object obj), Android's architecture of ListView/ExpandableListView (GroupIds, ChildIds) and on... My point is: Sets are just really bad (imho) to manipulate and make it work 100%.
I am tempted to change every single collection of my project to List as they work very well. The IDs for all my entities are generated through MYSQL's auto-generated sequence (#GeneratedValue(strategy = GenerationType.IDENTITY)).
Is there anyone out the who could in a definite way clear up my mind in all these little details mentioned above?
Also, is it doable to use Eclipse's auto-generated hashCode() and equals() for the ID field for every entity? Will it be effective in every situation?
Thank you very much,
Renato
List versus Set
Duplicates allowed
Lists allow duplicates and Sets do not allow duplicates. For some this will be the main reason for them choosing List or Set.
Multiple Bag's Exception - Multiple Eager fetching in same query
One notable difference in the handling of Hibernate is that you can't fetch two different lists in a single query.
It will throw an exception "cannot fetch multiple bags". But with sets, no such issues.
A list, if there is no index column specified, will just be handled as a bag by Hibernate (no specific ordering).
#OneToMany
#OrderBy("lastname ASC")
public List<Rating> ratings;
One notable difference in the handling of Hibernate is that you can't fetch two different lists in a single query. For example, if you have a Person entity having a list of contacts and a list of addresses, you won't be able to use a single query to load persons with all their contacts and all their addresses. The solution in this case is to make two queries (which avoids the cartesian product), or to use a Set instead of a List for at least one of the collections.
It's often hard to use Sets with Hibernate when you have to define equals and hashCode on the entities and don't have an immutable functional key in the entity.
furthermore i suggest you this link.

Hibernate Many to Many Relations Set Or List?

I have a many to many relationship at my Java beans. When I use List to define my variables as like:
#Entity
#Table(name="ScD")
public class Group extends Nameable {
#ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, fetch = FetchType.EAGER)
#JoinColumn(name="b_fk")
private List<R> r;
//or
private Set<R> r;
I get that error:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor#0'
...
When I use Set everything seem to work well.
I want to ask that when using many to many relationships which one to use for logical consept List or Set (because of list may have duplicates and set but what about performance and other issues)?
From relational databases perspective this is a set. Databases do not preserve order and using a List is meaningless, the order in them is unspecified (unless using so called indexed collections).
Using a Set also has great performance implications. When List is used, Hibernate uses PersistentBag collection underneath which has some terrible characteristics. I.e.: if you add a new relationship it will first delete all existing ones and then insert them back + your new one. With Set it just inserts the new record.
Third thing - you cannot have multiple Lists in one entity as you will get infamous cannot simultaneously fetch multiple bags exception.
See also:
19.5. Understanding Collection performance
Why Hibernate does "delete all then re-insert" - its not so strange
How about the uniqueness requirement from Set? Doesn't this force Hibernate to retrieve all objects each time one is added to the collection to make sure a newly added one is unique? A List wouldn't have this limitation.
I know the question was made years ago but I wanted to comment on this topic, just in case someone is doubtful about the set vs list issue.
Regarding lazy fetching, I think a bag (list without index) would be a better option due to the fact that you avoid retrieving all objects each time one is added to the collection to:
make sure a newly added one is unique, in case you are using a set
preserve order, in case you are using a list (with index)
Please correct me if I'm mistaken.

Persisting a Map<String,String> in ORMLite without resorting to DataType.SERIALIZABLE?

I've got a relatively simple class that is primarily backed by a Map<String,String>. I'd like to persist this class and be able search within the keys within the map. Based on this Stack Overflow question I get the feeling that Maps can only be persisted as a serialized blob.
I also see on the ORMLite website the following:
public class Account {
…
#ForeignCollectionField(eager = false)
ForeignCollection<Order> orders;
…
}
In the above example, the #ForeignCollectionField annotation marks
that the orders field is a collection of the orders that match the
account. The field type of orders must be either ForeignCollection
or Collection<T> - no other collections are supported. The
#ForeignCollectionField annotation supports the following fields:
Based on the above I get the impression that what I want isn't possible, but I thought I'd check here to be sure. I have it persisted in Hibernate, but I'd rather use something lighter like ORMLite!
One pretty easy solution is to have the getters and setters work with a JSONObject behind the scenes, and putting that object as a String in the database.
But then again, JSON isn't part of java-out-of-the-box so this may feel unneccesary if you're not using it anyway.
Yeah, there is no way in ORMLite to persist a Map. Keeping with the KISS principle, only the simple Collection class is supported. Set and Map have a lot more interface weight to them and will probably never be supported.
I don't have any super great work arounds for you. You could obviously use ForeignCollection and then have a local Map field that you create when you need to access the collection that way. Maybe an addOrder() method that would add it to the ForeignCollection and the Map.

Is it valid for Hibernate list() to return duplicates?

Is anyone aware of the validity of Hibernate's Criteria.list() and Query.list() methods returning multiple occurrences of the same entity?
Occasionally I find when using the Criteria API, that changing the default fetch strategy in my class mapping definition (from "select" to "join") can sometimes affect how many references to the same entity can appear in the resulting output of list(), and I'm unsure whether to treat this as a bug or not. The javadoc does not define it, it simply says "The list of matched query results." (thanks guys).
If this is expected and normal behaviour, then I can de-dup the list myself, that's not a problem, but if it's a bug, then I would prefer to avoid it, rather than de-dup the results and try to ignore it.
Anyone got any experience of this?
Yes, getting duplicates is perfectly possible if you construct your queries so that this can happen. See for example Hibernate CollectionOfElements EAGER fetch duplicates elements
I also started noticing this behavior in my Java API as it started to grow. Glad there is an easy way to prevent it. Out of practice I've started out appending:
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
To all of my criteria that return a list. For example:
List<PaymentTypeAccountEntity> paymentTypeAccounts = criteria()
.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)
.list();
If you have an object which has a list of sub objects on it, and your criteria joins the two tables together, you could potentially get duplicates of the main object.
One way to ensure that you don't get duplicates is to use a DistinctRootEntityResultTransformer. The main drawback to this is if you are using result set buffering/row counting. The two don't work together.
I had the exact same issue with Criteria API. The simple solution for me was to set distinct to true on the query like
CriteriaQuery<Foo> query = criteriaBuilder.createQuery(Foo.class);
query.distinct(true);
Another possible option that came to my mind before would be to simply pass the resulting list to a Set which will also by definition have just an object's single instance.

Categories