JPA: locking over #ManyToMany-relationship - java

Following situation: Using EJB on Glassfish, I have two entity classes: A and B. They are linked by a #ManyToMany relationship so I have an additional table A_B.
Now I'd like to work on an instance of A, i.e. also change some relations to class B. More precisely, I alter values in A from time to time, later (and in a different invocation of a Bean's method from the client) I want to submit the changes.
Therefor, I thought of using an optimistic lock on A's instance. The problem is: as the #ManyToMany relationship is stored in table A_B, A's entry in the DB would not alter, the version field would not get incremented, so summarized that approach does not work for me.
Locking entities in A_B would not work either as in a #ManyToMany new rows could be inserted that affect my two classes. I'd need some kind of range-based lock to achieve that no links between my instances of A and B are altered, added or deleted. Unfortunately, I did not find a proper solution for that problem.
What would be the best way to lock entities of A including all relationships to other entities?

Related

Get PersistentSet from EntityManager or Hibernate Session

Hibernate returns org.hibernate.collection.internal.PersistentSet as Set implementation on #OneToMany relation:
#OneToMany(mappedBy = "group", cascade = CascadeType.PERSIST)
private Set<Student> studentSet;
Hibernate tracks all changes on PersitanceSet (if some entity will is added to Set than it will be inserted into a database and etc.). Is it possible to have the same functionality for collections got by JPA EntityManager, org.hibernate.Session or by another way?
For example:
entityManager.createQuery(query, Student.class)
.setParameter("name", name)
.getResultList();
Doesn't return such kind of collection.
So I am searching the way to get elements by custom query and collect elements into a collection that Hibernates tracks all changes(inserting on adding new transient entities, updating on changing managed entities, deleting on removing from the collection)
What you're asking for is not possible in Hibernate.
Hibernate tracks all changes on PersitanceSet (if some entity will is added to Set than it will be inserted into a database and etc.)
That statement is not really accurate. Hibernate will not automatically insert an entity added to the set into a database. You need to opt in for that functionality specifically by declaring the appropriate cascading option (CascadeType.PERSIST in this case).
What Hibernate will do, however, is track associations between entities. If a collection represents the owning side of a to-many association, changes to the collection will establish/destroy associations between entities. In fact, Hibernate will track all other entity state, not just associations. That's the idea behind managed entities - to be able to work with a domain object just like with any other Java object, and let Hibernate take care about persistence behind the scenes.
A collection retrieved from a query does not represent part of a single entity state. Therefore, there would be little sense for Hibernate to track the structural state of the list. Suppose you made two queries for the same data within a single transaction. You then modify one of the result lists and leave the other intact. What do you think should happen in such a scenario?
Note that by 'not possible', I mean to say that Hibernate does not provide such a functionality out of the box. However, if you want to track changes to an arbitrary list, there are list implementations that allow that (see e.g. Glazed Lists or Apache Commons Events). You could combine them with Hibernate API to get the behavior you want.

JPA: Event notification during persisting/updating a child?

I have two entities A and B. A has a many-to-one association towards B (A.listOfBs::List). I want to validate before B is persisted if a B was added to an already existing A.
Debugging into our JPA implementation (Hibernate), I learned that it basically cascades the association and while knowing its a parent<->child association only invokes the PrePersist-handler on B and never the BeforeUpdate on A.
Since I do not want to introduce a bi-directional mapping, I would like to know how I can validate A's children during B's persisting phase as A has special requirements (no two childs sharing the same type).
Is there any mechanism I can learn about parent<->child related events revolving around persisting or deleting children of a particular parent?
From debugging into Hibernate (another framework might be different), the persist event is handled solely on a per entity level. There is a mapping between child and parent in the persistence context that is set prior to persisting the entity (see handling/persisting an association). If one is able to access it, it would be possible for the child to notify its parent event even without a bi-directional connection. All this will continue to feel like a hack.
The best solution seems to be to listen to session level events and iterate through the list of managed entities an let those be validated regardless whether those have changed or not.

How one to many relationship gets persisted in JPA if i have thousands of related entities already in data base and i add new entities in collection

We have two entities Entity1 and Entity2, where Entity1 contains set of Entity2,
we already have thousands of entities stored in database of entity type Entity2 which all are referenced from an instance of Entity1, say myEntity.
Now if i add more Entity2 entities to the collection and try to persist myEntity, where newly added entities of Entity2 are already persisted.
My question is how will be the behavior on persist of myEntity , whether existing members of relation will travel to memory and new members will be added or new members are added to database without bringing existing members to memory
If you have thousands of referenced entities, it might be better not to map the relationship and instead only query for it when needed - allowing you to use paging or other mechanisms to reduce the amount of entities read in at a time. It depends on what type of mapping it is, but only the owning relationship needs to be mapped (the one that doesn't have the mapped by) to set the foreign key in the database. Set the Entity2 side to be the owning side if it isn't already.
If this is a M:M with a relation table and doesn't make sense to map from the Entity2 side instead - you could add an entity for the relation table that you would read in the same way. The new entity would have a reference to Entity1, but Entity1 wouldn't reference it, and the app would query for the new entity when it needs to get Entity2s associated to a specific Entity1.
If you want to add new instances to a relation between two already existent entities (a one to many in this case) then you must first fetch from the database the entity that contains the collection; in your case myEntity.
So, when you load that entity you are bringing it to memory. If you had defined the relation between those two as EAGER then all the related entities (the ones in the collection) will be fetched as well at the same time than the parent one. If you, otherwise, had defined the relation as LAZY then the related entities will be loaded when you access the collection (in other, words, when you invoke the getter getXXX method for that collection).
This happens that way because JPA implementations (now I'm thinking on Hibernate) return proxies of the entities instead of actual instances so they can intercept the getter/setter method calls and perform any tracking on the state of the entities.
Right, so now you want to add more instances to the relation. It doesn't matter whether the relation is EAGERor LAZY in this case as you will eventually invoking the getter method of the collection in order to be able to perform add(myNewEntity); on it. So, the already existent entities are in the collection and you are just adding a (probably) untracked entity under the collection implementation semantics.
When persisting myEntity back to the database the JPA implementation will know which instances of the actual collection need either an update, a delete or an insert. If you just added new instances then just insert statements will be issued but you could also remove an entity from the collection or change the state (invoke the setter) of an already existent instance. JPA implementations are able to recognise those operations and issue the appropriate SQL statements to keep the database up to date.

JPA mapping for inserting a relationship

I am using JPA to persist my entities. Suppose I have a ManyToMany relationship between the entity A and B. So, in the class A it will be a List<B> and in B a List<A>.
My question is about the efficiency of adding a new relationship.
In the easy way I can make a add(new B()) in the list in class A. Will this List of B objects in the class A will all be loaded from the database when I call the add method in runtime? Is this efficient?
If I have 200 relationships, it will load all of them, to simply add a new object B? It will be better to create a native query to insert a new row the ManyToMany table.
The behavior of add() on a List is dependent on the JPA provider.
For EclipseLink, for a LAZY List relationship add() will not cause the list to be fetched by default.
Usually, JPA providers provide their own implementations of Java Collections which support lazy loading, so not all relationships will be loaded right from the start.
Also, when you modify any of the lists as you described, the JPA provider should transparently update the database. You don't have to worry to keep things consistent, other than references you might have cached on your own.
When it starts to run into the hundreds you might be better off to just map the join table as a JPA entity and not use a ManyToMany mapping but simply perform operations (mutations and selections) directly on the join table with two ManyToOne mappings in there.

What are JPA entities?

I am starting to use JPA and I always get confused with the term of entities and their usage, I have read a lot but I still don't quite get it.
I read the Oracle documentation of it but it does not really explain its role in the transaction.
What are JPA enities? does they actually hold the data for each row, I mean, are they stored instances that hold the row data? or they just map tables of the db and then insert and delete in them?
for example if I use this:
entity.setUserName("michel");
Then persisting it, then changing the user name, and persisitig it again (i.e merging it)
Does this change the previously entered user name? or does it create a new row in the db?
An Entity is roughly the same thing as an instance of a class when you are thinking from a code perspective or a row in a table (basically) when you are thinking from a database perspective.
So, it's essentially a persisted / persistable instance of a class. Changing values on it works just like changing values on any other class instance. The difference is that you can persist those changes and, in general, the current state of the class instance (entity) will overwrite the values the row for that instance (entity) had in the database, based on the primary key in the database matching the "id" or similar field in the class instance (entity).
There are exceptions to this behavior, of course, but this is true in general.
It's a model. It's a domain object that can be persisted. Don't over think it. Akin to a Rails model. And remember, models (in this paradigm) are mutable!

Categories