I have two entities: UserAccount
and Notification
. These have a relationship as shown below.
public class UserAccount {
@Id
@
I faced this problem not so long ago...
I found this article: Performance Antipatterns of One To Many Association in Hibernate https://fedcsis.org/proceedings/2013/pliks/322.pdf
in short:
List
/ Collection
+ @OneToMany
-> One Element Added: 1 delete, N inserts , One Element Removed: 1 delete, N insertsList
+ @OneToMany
+ @IndexColumn
/ @OrderColumn
-> One Element Added: 1 insert, M updates, One Element Removed: 1 delete, M updatesSet
+ @OneToMany
-> One Element Added: 1 insert , One Element Removed: 1 deleteFor me: yes that mean that you have to change your List
to Set
for unidirectional @OneToMany
. So I changed my model to match with Hibernate expectations and that cause a lot of issues because the view part of the application was relying on List
mostly...
In one hand the Set
is a logical choice for me because there are no duplications, in the other hand List
were easier to deal with.
So JPA/Hibernate forced me to change the model object and that was not the first time, when you are using @EmbededId
you do something that you probably won't do in the same way without JPA/Hibernate. And when you have to be aware of HibernateProxy
in all the application especially in equals methods ... else if(object instanceof HibernateProxy) {
..., you notice the JPA/Hibernate persitence layer is a little bit intrusive in others layers.
But when I use directely JDBC I also use to change the model or the buisness methods to facilitate the persistence... Layers isolation is may be a dream or cost too much to be done at 100%?
And you can order a Set
if they are SortedSet
like TreeSet
with the annotation @OrderBy
That bring a problem when some code rely on List
and cannot be changed (such as JSF/PrimeFaces <dataTable>
or <repeat>
components)
So you have to change your Set
into List
and go back to Set
but if you do setNotifications(new HashSet<>(notificationList))
you will have extra queries because the set is a org.hibernate.collection.PersistentSet
managed by Hibernate... So I used addAll()
and removeAll()
instead of setters:
protected <E> void updateCollection(@NonNull Collection<E> oldCollection, @NonNull Collection<E> newCollection) {
Collection<E> toAdd = new ArrayList<>(newCollection) ;
toAdd.removeAll(oldCollection) ;
Collection<E> toRemove = new ArrayList<>(oldCollection) ;
toRemove.removeAll(newCollection) ;
oldCollection.removeAll(toRemove) ;
oldCollection.addAll(toAdd) ;
}
Mind the equals()
and hashCode()
methods of your @Entity
...
One other problem is that you need to Master both JPA and Hibernate if you want to use JPA with Hibernate as the implementation because the Set/List/Bag semantic is from Hibernate not from JPA (correct me if I'm wrong)
A specification is made for abstracting the implementation to not depend on one specific vendor. Although most of JavaEE specs succed, JPA failed for me and I gave up to be independent of Hibernate
List: Allows duplicate elements in it.
Set: All elements should be unique.
Now, delete may be happening because you are over-writing element in list, and so when you modify persisted entity of UserAccount type, it is removing the entity which is in list previously.