JPA mapping for inserting a relationship - java

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.

Related

Why we should use Spring Data JPA mappings?

This can seem a stupid questions for some people, but I couldn't find any information anywhere why we should use mappings (#OneToOne, #OneToMany etc) in JPA while defining entity classes. I know one the advantage is code reduction, so that we don't have to explicitly write queries in order to fetch data from relationship tables. But is there any other benefit (from code optimisation perspective at SQL side) that we have?
The reason is to load object trees or graphs.
That's the goal of object-relational mapping to fill the gap between database tables and objects.
And as you said it reduces code.
In a summary the idea of the ORM is to map tables to objects, so the developer works with the objects instead of the tables.
Tables in SQL have relationships through key columns.
in JPA these relationships are expressed via #OneToMany, #OneToOne etc.
This means that if you want to fetch a row from one table and join that with corresponding row from another table (via a relationship) the JPA implementation (mostly Hibernate) can do that for you, looking at the relationships you have defined for your entities.
You need to describe the entities relationships because it's part of the DB schema model which you are mapping to application level objects. As you mention - it saves you writing the SQL queries yourself, but that's not the main point.
The main point is that you can model/represent one domain (database tables, rows, relationships, SQL commands) as another type of domain (objects/classes, OOP paradigm, programming language commands) which completely shifts the way you work with it.

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.

Whats the safest way to remove lazy initialization proxies generated by Hibernate?

I would like to keep the Parent/Child relationship but when I parse through the Parent Object I don't want to fetch the child elements.
Proxies are generated so that Hibernate can intercept calls to uninitialized associations and try fetching them on-demand.
The LazyInitializationException is a code smell. You get it because you haven't properly initialized all the required entity associations prior to closing a Session. Switching to EAGER associations is also a bad idea because the fetching policy is a query responsibility.
Try to reduce the number of associations if you don't need them and use queries instead. You can build an application with just many-to-one associations (mirroring the FK relations) and instead of one-to-many associations you can have DAO methods.
As for this statement:
I would like to keep the Parent/Child relationship but when I parse
through the Parent Object I don't want to fetch the child elements.
If you keep the Parent/Child relationship you always need to load the association prior to using it. Trying to remove the proxies sounds like you are trying to hack a solution instead of properly design your application layers.
So Proxies are fine and they allow you to improve the application performance, because you don't always fetch all associations when you try to access a root entity.
To disable proxies you just have to annotate your entities with the Proxy annotation:
#Proxy(lazy=false)

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: locking over #ManyToMany-relationship

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?

Categories