JPA OneToOne Lazy relation - java

I have 2 entities: User and UserProfile that have a bidirectional #OneToOne relationship between them.
Due to some old DB Design the UserProfile is the owner (i have the column user_id in users_profiles table)
The relationship is Lazy as I have fetchType Lazy and optional = false.
Everything works as expected, I mean when I load an UserProfile it does not automatically loads the User also. I guess this is perfectly normal as I load from the owner side.
My problem is that if I load a User (owned side) it loads automatically the UserProfile although the relationship is lazy.
I mean: Is this normal that when I load an entity from the owned side to load the owner entity also ?
#Entity
#Table(name = "users")
public class User extends BaseEntity implements Serializable {
#OneToOne(mappedBy = "user", optional=false, fetch = FetchType.LAZY)
private UserProfile profile;
// .................rest of entity
}
#Entity
#Table(name="users_profiles")
public class UserProfile extends BaseEntity implements Serializable {
#OneToOne(optional=false, fetch = FetchType.LAZY)
#JoinColumn(name="user_id")
private User user;
// ... rest of entity here
}
The way that I test this is by loading the User entity with EntityManager method find(id).
I have noticed that when the relation is not lazy I have only one query with a join inside. If I put the current setup I have two individual queries: 1 for user and the other one for profile.

It is important to realize, that lazy loading behavior is not enforced by JPA specification, it is only recommended. It is up to hibernate as the implementation to choose if it is supported and under which conditions.
Hibernate usually does its best to load the data lazily when requested, but in case of one-to-one mapping, when the relationship is stored in another table (the primary key is in table users_profiles), it needs to query also the second table to retrieve the primary key to create a proxy object. In fact, it does not retrieve only id, but full row and creates the UserProfile in eager way, because it costs almost nothing to fetch additinal data when the table needs to be joined in any case.
The answer for Hibernate: one-to-one lazy loading, optional = false suggests that making relationship non-optional should make it lazy, but I doubt it is true. Hibernate would need to create a proxy without an ID, which is doubtfully correct in all cases. One case where that would fail is when you remove the proxy object from the collection in parent entity, and then try to read its data - as the proxy itself does not carry enough information to retrieve data lazily, it is not possible without connection to parent entity.

This is normal, by default, hibernate creates run-time proxies. It loads the objects as a proxy unless a fetch mode is specified or set to false.
for example, load() always retrieves proxy objects. If called more than once within same session, it reads data from persistent context cache. That's because once the object is loaded in cache, the next subsequent calls perform repeatable read.

Related

Spring JPA generates SELECT query for new associated entities of existing owning entity

I have an owning entity class with some associated entities, e.g.
#Entity
public class Parent {
#Id
#GeneratedValue
private UUID id;
#OneToMany(mappedBy = "parentId", cascade = CascadeType.ALL)
List<Child> children;
...
}
#Entity
public class Child {
#Id
#GeneratedValue
private UUID id;
private UUID parentId;
...
}
I am using Spring Boot Starter Data JPA. I traced the code to the SimpleJpaRepository class, I noticed that on calling save(parent), it checks if isNew() returns true, Spring will call persist(); otherwise it calls merge(). This makes total sense, as persist() will generate only an INSERT, while merge() will generate a SELECT (if it hasn't done before) and then followed by an INSERT if the SELECT returns nothing; otherwise an UPDATE.
The above works well when saving a new Parent with new Child, only INSERTs are generated without any SELECT.
However, my problem is, when creating some new Child and adding them to an existing Parent, then on saving the parent, somehow I noticed Spring JPA is still generating an extra SELECT for each of these new Child entities before the INSERTs, which I found unnecessary.
Is there a way to avoid these SELECT queries?
Further investigation I found that if I leave the id of the Child null (i.e. let it auto generates a new id), then only INSERT is generated. However, if I manually assign an id to a Child, then a SELECT will be generated before an INSERT. Is there a way I can assign id to Child while avoiding the extra SELECT?
On the basis of your code i think because of OnetoMany mapping and you did't provide cascade type then it not happen
select query running two times
provide more information
full code of Entity classes
properties file

Does FetchType.LAZY fetch anything in list or it's empty

Let's say i have a association as ,
class Department{
......
#OneToMany(fetch = FetchType.LAZY)
private List<Employee> employees;
}
Now when i fetch Department, will it fetch anything in employees list or will it be completely empty.
Will identifiers for employee object be loaded in list like say i have employee object attributes as below:-
Employee{
id
name
doj
....
}
Lazy object like {
id -> 111
name -> null
doj -> null
}
Now when i initialize employee object or access it's properties using getters, then the object will be loaded from database using id as an identifier...??
Instead of the real collection class (e.g. ArrayList) a different List implementation is injected into your field (PersistentList). Depending on the calls on that collection and the lazy strategy it will do different things:
In case lazy="lazy" the call to any of the collections methods would get the collection fully loaded
If lazy="extra", then calls to some functions would trigger SQL without loading the collection. E.g. list.size() would trigger select count.... While getting the 1st element would select only that element. This may be suitable for large collections. Note, that this behaviour may also depend on the collection type - unordered collections will load all elements anyway.
Lazy fetch type, Hibernate won’t load the relationships for that particular object instance.
FetchType.LAZY = Doesn’t load the relationships unless explicitly “asked for” via getters
FetchType.EAGER = Loads ALL relationships
In your case It won't load Employee List from database unless you explicitly fire query for it, Because you have set fetch type ( fetch = FetchType.LAZY ). If fetch type was ( fetch = FetchType.EAGER ) then It would explicitly fire a select query for Employee list. In that object you would get all employee property eg name, doj.
the object will be loaded from database using id as an identifier...??
Department{
#OneToMany(fetch = FetchType.EAGER,,mappedBy = "department")
private List<Employee> employees;
}
In Emplooyee.... You need to mapped it by reference of department object.
eg:
Employee{
// Reference of department.
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "departmentid", nullable = false)
private Department department;
}
This way it will become bidirectional. now Hibernate will fire query by reference (id in native sql) .
If you want to be loaded lazily the set Fetch mode FetchType.LAZY in both mapping....
In your case until you explicitly access Department.employees (through a getter or any other means) It will not load the Employee entities. There will be a Proxy for this. It will be initialized once at the first call to access this employees collection.
How Lazy Loading Works in Hibernate
The simplest way that Hibernate can apply lazy load behavior upon your entities and associations is by providing a proxy implementation of them. Hibernate intercepts calls to the entity by substituting a proxy for it derived from the entity’s class. Where the requested information is missing, it will be loaded from the database before control is ceded to the parent entity’s implementation.
Please note that when the association is represented as a collection class, then a wrapper (essentially a proxy for the collection, rather than for the entities that it contains) is created and substituted for the original collection. When you access this collection proxy then what you get inside returned proxy collection are not proxy entities; rather they are actual entities. You need not to put much pressure on understanding this concept because on runtime it hardly matters.
Please refer this for more information:
http://howtodoinjava.com/hibernate/lazy-loading-in-hibernate/
Also enable hibernate.sql.show=true so that you can see what queries are being fired when you are trying to fetch the collections.

Many to many bidirectional mapping in JPA

I have the following JPA entities.
A profile have many users and a user have many profiles:
#Entity
public class Profile implements Serializable {
#Id
private Long id;
#ManyToMany(cascade = CascadeType.ALL)
private List<User> users;
...
}
#Entity
public class User implements Serializable {
#Id
private Long id;
#ManyToMany(mappedBy = "users")
private List<Profile> profiles;
...
}
On my application, when a user is merged, the profiles are updated on database.
However, when a profile is merged, the users are not updated.
Is possible to map my entities in order to make both sides merge their lists?
I am using JPA 2.1 and Hibernate.
Your Profile entity is ownind side or relationship. It's up to it, to manage relationship, so in order to update User you'll have to update Profile too or make manual SQL calls.
Java Specification for JPA 2.1 says that:
• For many-to-many bidirectional relationships either side may be the owning side
So if you'd like to make both entities editable from both side, remove mappedBy element and assigne necessacy cascade. But I'm not sure it works in Hibernate (didn't try actually), see this docs on mapping, there's no information about m:m without owning side: http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch07.html#collections-bidirectional
Otherwise, you may need to iterate through collection in Profile entity and then change them. For example:
for( User user : profile.getUsers() ) {
user.setSomething(.....);
}
session.merge(profile);
Changing List to Set might be needed in order to avoid Hibernate's delete and reinsert, described here: http://assarconsulting.blogspot.fr/2009/08/why-hibernate-does-delete-all-then-re.html
Also, don't forget about equals() and hashCode() methods override

Efficiently determining the IDs of entities referenced via OneToMany relationship

Let's say I have a Hibernate entity that declares a OneToMany relationship to a different entity:
#Entity
public class SomeEntity {
#OneToMany(fetch = FetchType.LAZY)
private List<OtherEntity> otherEntities = new LinkedList<OtherEntity>();
[...]
}
When mapping SomeEntity to the corresponding DTO, all I need are the IDs that identify OtherEntity as primary key (i.e., I am not actually interested in OtherEntity instances).
Does Hibernate support this pattern, i.e., only retrieving the IDs of entities referenced via a OneToMany relationship?
I cannot influence how SomeEntity is retrieved (i.e., I have an existing SomeEntity instance retrieved within te scope of the current Hibernate session), but let's assume that lazy loading has not yet taken place, so just retrieving the child objects' IDs (rather than the complete objects) would actually yield a performance benefit.
Well, if you only need the entities' ids and you want to be economical about it, when you get those entities from the database you should state in your query that you only want to get the ids of each entry, using projections, something like :
SELECT Entity.id as entity FROM Entity WHERE ...
This will return an array of objects of the same type as Entity's id field type.
You can try obtaining the primary key without accessing the entity itself (without otherEntities.get(0).getId()). To do this you can use the PersistenceUnitUtil class:
PersistenceUnitUtil#getIdentifier(yourEntity)
The PersistenceUnitUtil can be obtained from the EntityManagerFactory. So it could be something like:
EntityManager em = ...
PersistenceUnitUtil = em.getEntityManagerFactory().getPersistenceUnitUtil();
Unfortunately, I'm not aware if this will prevent the entity loading from occuring. However, just accessing the otherEntities collection or even obtaining references to each entity will not make the instance to be loaded; you need to invoke a method on the fetched entity in order to be sure it will be loaded.
You also might consider creating a #NamedQuery and return only the OtherEntity ID's.
HTH!
From hibernate reference, section 2.2.2.1.
http://docs.jboss.org/hibernate/annotations/3.5/reference/en/html/entity.html#entity-mapping-property
Declare your columns as lazy initialized:
#Basic(fetch = FetchType.LAZY)
private String getYourProperty() {
}
You also need to disable proxies for your entity class and byte instrument it. There is an example here:
Making a OneToOne-relation lazy
You can use the below HQL as told in the documentation to establish this.
session.createQuery(select new OtherEntity(oe.id) OtherEntity oe
where oe.parentSomeEntity.someId = :someId).list();//also set someId.
Add a constructor in OtherEntity to set the id also there should be a mapping to SomeEntity in OtherEntity.
This HQL will give you a List<OtherEntity> with only id set in the bean.

JPA eager fetch does not join

What exactly does JPA's fetch strategy control? I can't detect any difference between eager and lazy. In both cases JPA/Hibernate does not automatically join many-to-one relationships.
Example: Person has a single address. An address can belong to many people. The JPA annotated entity classes look like:
#Entity
public class Person {
#Id
public Integer id;
public String name;
#ManyToOne(fetch=FetchType.LAZY or EAGER)
public Address address;
}
#Entity
public class Address {
#Id
public Integer id;
public String name;
}
If I use the JPA query:
select p from Person p where ...
JPA/Hibernate generates one SQL query to select from Person table, and then a distinct address query for each person:
select ... from Person where ...
select ... from Address where id=1
select ... from Address where id=2
select ... from Address where id=3
This is very bad for large result sets. If there are 1000 people it generates 1001 queries (1 from Person and 1000 distinct from Address). I know this because I'm looking at MySQL's query log. It was my understanding that setting address's fetch type to eager will cause JPA/Hibernate to automatically query with a join. However, regardless of the fetch type, it still generates distinct queries for relationships.
Only when I explicitly tell it to join does it actually join:
select p, a from Person p left join p.address a where ...
Am I missing something here? I now have to hand code every query so that it left joins the many-to-one relationships. I'm using Hibernate's JPA implementation with MySQL.
Edit: It appears (see Hibernate FAQ here and here) that FetchType does not impact JPA queries. So in my case I have explicitly tell it to join.
JPA doesn't provide any specification on mapping annotations to select fetch strategy. In general, related entities can be fetched in any one of the ways given below
SELECT => one query for root entities + one query for related mapped entity/collection of each root entity = (n+1) queries
SUBSELECT => one query for root entities + second query for related mapped entity/collection of all root entities retrieved in first query = 2 queries
JOIN => one query to fetch both root entities and all of their mapped entity/collection = 1 query
So SELECT and JOIN are two extremes and SUBSELECT falls in between. One can choose suitable strategy based on her/his domain model.
By default SELECT is used by both JPA/EclipseLink and Hibernate. This can be overridden by using:
#Fetch(FetchMode.JOIN)
#Fetch(FetchMode.SUBSELECT)
in Hibernate. It also allows to set SELECT mode explicitly using #Fetch(FetchMode.SELECT) which can be tuned by using batch size e.g. #BatchSize(size=10).
Corresponding annotations in EclipseLink are:
#JoinFetch
#BatchFetch
"mxc" is right. fetchType just specifies when the relation should be resolved.
To optimize eager loading by using an outer join you have to add
#Fetch(FetchMode.JOIN)
to your field. This is a hibernate specific annotation.
The fetchType attribute controls whether the annotated field is fetched immediately when the primary entity is fetched. It does not necessarily dictate how the fetch statement is constructed, the actual sql implementation depends on the provider you are using toplink/hibernate etc.
If you set fetchType=EAGER This means that the annotated field is populated with its values at the same time as the other fields in the entity. So if you open an entitymanager retrieve your person objects and then close the entitymanager, subsequently doing a person.address will not result in a lazy load exception being thrown.
If you set fetchType=LAZY the field is only populated when it is accessed. If you have closed the entitymanager by then a lazy load exception will be thrown if you do a person.address. To load the field you need to put the entity back into an entitymangers context with em.merge(), then do the field access and then close the entitymanager.
You might want lazy loading when constructing a customer class with a collection for customer orders. If you retrieved every order for a customer when you wanted to get a customer list this may be a expensive database operation when you only looking for customer name and contact details. Best to leave the db access till later.
For the second part of the question - how to get hibernate to generate optimised SQL?
Hibernate should allow you to provide hints as to how to construct the most efficient query but I suspect there is something wrong with your table construction. Is the relationship established in the tables? Hibernate may have decided that a simple query will be quicker than a join especially if indexes etc are missing.
Try with:
select p from Person p left join FETCH p.address a where...
It works for me in a similar with JPA2/EclipseLink, but it seems this feature is present in JPA1 too:
If you use EclipseLink instead of Hibernate you can optimize your queries by "query hints". See this article from the Eclipse Wiki: EclipseLink/Examples/JPA/QueryOptimization.
There is a chapter about "Joined Reading".
to join you can do multiple things (using eclipselink)
in jpql you can do left join fetch
in named query you can specify query hint
in TypedQuery you can say something like
query.setHint("eclipselink.join-fetch", "e.projects.milestones");
there is also batch fetch hint
query.setHint("eclipselink.batch", "e.address");
see
http://java-persistence-performance.blogspot.com/2010/08/batch-fetching-optimizing-object-graph.html
I had exactly this problem with the exception that the Person class had a embedded key class.
My own solution was to join them in the query AND remove
#Fetch(FetchMode.JOIN)
My embedded id class:
#Embeddable
public class MessageRecipientId implements Serializable {
#ManyToOne(targetEntity = Message.class, fetch = FetchType.LAZY)
#JoinColumn(name="messageId")
private Message message;
private String governmentId;
public MessageRecipientId() {
}
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
public String getGovernmentId() {
return governmentId;
}
public void setGovernmentId(String governmentId) {
this.governmentId = governmentId;
}
public MessageRecipientId(Message message, GovernmentId governmentId) {
this.message = message;
this.governmentId = governmentId.getValue();
}
}
Two things occur to me.
First, are you sure you mean ManyToOne for address? That means multiple people will have the same address. If it's edited for one of them, it'll be edited for all of them. Is that your intent? 99% of the time addresses are "private" (in the sense that they belong to only one person).
Secondly, do you have any other eager relationships on the Person entity? If I recall correctly, Hibernate can only handle one eager relationship on an entity but that is possibly outdated information.
I say that because your understanding of how this should work is essentially correct from where I'm sitting.

Categories

Resources