Why can't hibernate lazily fetch #ManyToOne and #OneToOne? - java

After some frustrating issues and tests, I've read that hibernate can't lazily fetch ToOne relationships.
From what I've read, hibernate lazily fetches ToMany by setting its own Set as a proxy, and when a method is called on that Set, it fetched the data in the database before performing the action. Fine.
For ToOne, the reason I've seen is that since the attribute can be null (unlike ToMany), hibernate has to know whether it needs to populate it with null or a proxy, and that hibernate cannot know that without querying the other table. And since it has to query that other table, it eagerly fetches the data at the same time.
I find that rather stupid. I can understand it on the non owning side of the relationship, where nothing in the table indicates whether the toOne is populated, but on the owning side, the table contains a column with the foreign key, which is either null or not.
Why can't hibernate query the table and set the attribute to either null or a proxy depending on the value from that column? It doesn't need to check the second table, if your column is not null, you know the second table has a corresponding entry (and if it hasn't, you have an integrity problem and hibernate should just throw).

Hibernate behaves more or les how you descibed.
On the owning side hibernate supports Lazy loading, it's just not enabled by default. You need to add it #OneToOne(fetch = FetchType.LAZY)
But when you have that mapped bidirectionaly (on both entities), as you said hibernate needs to query the table to decide between null or proxy. So devs decided to eager load the whole entity. Regardless of the fetch type.
You can avoid theese problems by getting rid of the foreign key and just use same primary key vaue.
You can do that with #MapsId annotation on the owning side.
#Entity
public class Owning {
#Id
private Long id;
#OneToOne
#MapsId
#JoinColumn(name = "id")
private Child child;
}

Related

Saving an array of Entities in another entity with Hibernate

I have a Task entity that should contain an array of User entities in a #OneToMany relationship.
But I can't figure out a way to store said array without having a link table, since a User may be referenced in multiple Tasks.
The relationship should look like such, in TaskEntity:
#OneToMany(mappedBy = "user")
private Set<UserEntity> users = new HashSet<>(0);
What would be the proper way of doing it? How can a single row save an array of entities?
You can avoid join table (but it is not advised to do so, see below) for unidirectional one-to-many relationship. It would require foreign key to be on the target side of relationship(many side of relationship). You would need to specify a #JoinColumn annotation to point to the foreign key column.
#OneToMany
#JoinColumn(name="TASK_ID")
private Set<UserEntity> users = new HashSet<>(0);
It is not advisable, because of the following :
1) Performance : if both UserEntity state and Task states are changed, upon writing to UserEntity the FK to Task is not known, because UserEntity does not have reference to it. So in this case UserEntity might be written twice, once for UserEntity changes and once for Task changes.
2) Mapping : if UserEntity is assigned to a different task, and there is no reference back to Task from UserEntity, there will be no changes in context.
So it is advisable to go for Join Table in your case.
So a User can have many Tasks and each Task can have many Users.
Sounds like a classic fan-trap, you will need a link table and to use #ManyToMany.
However the Data-Structure should be modeled before looking into data access implementation.
What you have described is a Many to Many relationship, and your database structure should reflect that, before you think about how you can retrieve the data with Hibernate.

CascadeType vs FetchType

I would like to now what is the difference between CascadeType and FetchType in Hibernate?
They seem very similar but I guess they are not interchangeable, right?
When to use them? Can they be used both at the same time?
These are 2 different things:
The CascadeType in Hib. could be REFRESH, MERGE, ..., ALL you put it under the related entity and it determines the behavior of the related entity if the current entity is: refreshed, updated, deleted, e.t.c.. So whenever you entity is affected the CascadeType tells if the related entity should be affected as well.
The FetchType could be only of 2: EAGER and LAZY. This one you as well put under the related entity and it determines whether the related entity should be initialized right away when the current entity is initialized (EAGER) or only on demand (LAZY).
Cascading is used for propagating entity state transitions from a Parent entity to a Child.
Fetching is used for loading associated entities and you can have:
global fetch policies (defined through entity mapping)
query-time fetch policy (using the HQL/JPQL FETCH directive)
Both are different configurations, you can relate it with simple SQL.
Cascade tells you what happens when one entity gets updated ( on delete cascade in sql)
Fetch tells how the query is going to be executed ( join, lazy ...)
There's a big difference between the two of them.
CascadeType is a property used to define cascading in arelationship between a parent and a child.
FetchType is a property used to define fetching strategies which are used to optimize the Hibernate generated select statement, so that it
can be as efficient as possible.
You can find more about them in:
Hibernate – fetching strategies examples
Hibernate JPA Cascade Types

What is difference between Hibernate EAGER fetch and cascade-type all

Please explain difference between hibernate Eager fetching and cascade-type all.
In both configuration we can load child object associated with its parent, then what is difference between in.
Its simple :Consider two entities 1. Department and 2. Employee and they have one-to-many mappings.That is one department can have many employee
cascade=CascadeType.ALL and it essentially means that any change happened on DepartmentEntity must cascade to EmployeeEntity as well. If you save an Department , then all associated Employee will also be saved into database. If you delete an Department then all Employee associated with that Department also be deleted.Cascade-type all is combination of PERSIST, REMOVE ,MERGE and REFRESH cascade types. Example for Cascade type All
Fetch type Eager is essentially the opposite of Lazy.Lazy which is the default fetch type for all Hibernate annotation relationships. When you use the Lazy fetch type, Hibernate won’t load the relationships for that particular object instance. Eager will by default load ALL of the relationships related to a particular object loaded by Hibernate.Click here for an example.
Cascading and fetching are orthogonal concerns.
Cascading is about propagating an entity state transition from a Parent entity to a Child, simplifying the data access code by allowing the ORM tool to persist/merge/remove dependent associations on out behalf.
EAGER fetching is a mapping-time association loading decision, because it instructs Hibernate to always retrieve depended associations whenever a root entity gets loaded. Query-time fetching is preferred, because it gives you better flexibility and while the LAZY fetching mapping policy can be overridden by the FETCH directive. With EAGER fetching your are stuck, because you can't override it at query time and Hibernate will always fetch the association, even if on some use cases you don't need it.

Hibernate Annotation Confusion

Recently, I have been learning about Hibernate, and I am facing some difficulties. My first problem is as follows: I am very much confused with the below terms.
Bidirectional mapping
Many to One
Because, as far as I know, in rdbms we first need to insert in parent table. Then we can insert on child table, so the only possible scenario is one-to-many (first parent then children). Then, how is many-to-one is going to work? Second, what is this bidirectional mapping in regards to Hibernate. Specifically, different types of join annotations confuse me a lot. I am listing those annotations below.
1.#JoinTable(name = "Tbale_Name", joinColumns = { #JoinColumn(name = "Column_Name") },
inverseJoinColumns = { #JoinColumn(name = "Another_ColumnName") })
2.#OneToMany(mappedBy="department")` this mappedby term
3.#PrimaryKeyJoinColumn
Please help me understand these concepts.
The first thing I would say is don't think in terms of tables but think in terms of Objects.
What you are trying to express with the annotations is the relationship between objects, let hibernate work out how to persist the data. You can obviously manually check the SQL but the idea of using an ORM is to map the relationships between entities accordingly and let the ORM figure out the complexity around generating SQL etc.
Its worth noting that the parent -> child relation can be mapped using #ManyToOne by adding mappedBy to the non-owning (child) side of the relationship. Hibernate then will determine which entities to insert into the database first. Running with a TransactionManager will enforce integrity with multi table inserts. Hibernate will also workout which entities need to be persisted, for example if you add an new object on the many side to an existing object on the one side.
Furthermore, its worth understanding that in some cases it won't always be the database that generates the primary key in a parent -> child foreign key. Its possible for the code to generate the Identifier and hibernate will persist them according.
Bidirectional mapping means that object entities have a reference to each other. i.e. You can retrieve the second entity from the first entity. Bidirectional mapping supports one-to-many
or many-to-many. I.e. OneToMany = a Set on one of the entities. Many-To-Many = Sets on both entities.
JoinTable tells hibernate that a table in the database can be used to map to other tables together. See JPA "#JoinTable" annotation for more information. JoinColumn tells hibernate what column to use to make the join between the two entities. Hibernate needs these to construct the SQL.

Hibernate: merge with many-to-many results in StackOverflowError

I have a many-to-many relationship were the link table has an additional field. Hence the relationship is done with 2 one-to-many relations according to below tutorial:
http://www.mkyong.com/hibernate/hibernate-many-to-many-example-join-table-extra-column-annotation/comment-page-1/#comment-122181
I have the 2 entities, a third entity which defined the link table and consist of an #Embeddable ID field.
The relationship is defined as:
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.compound", cascade = CascadeType.ALL)
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.structure", cascade = CascadeType.ALL)
were pk = the #Embeddable ID field. Insert and deleting works fine however when I call
session.merge(compound);
I get a StackOverflowError and log shows that hibernate is making tons of select statements. Note that database contains exactly 1 association, eg. 1 compound containing 2 structures. It looks like hibernate gets into a endless loop.
I've seen this solution also on http://giannigar.wordpress.com/2009/09/04/mapping-a-many-to-many-join-table-with-extra-column-using-jpa/ but how do you do updated with this?
My solution was to use FetctType.EAGER on the owning side and FetchType.Lazy on child side and in the 2 ManyToOne relations in the link table. Like this I can load from the owning side without getting LazyInitializationException and mergign working as expected.
I second SpaceTuckker's answer. I don't think Persist is the same as merge. Merge will load the object before persisting it. Persist doesn't. So when you call merge IMHO it needs to load the lazy relation. If you call persist it does not.
You might also use #ElementDependent to mark related #OneToMany relations as depending on another table. This was the way I solved the Many-To-Many relation with additional columns in the join table.

Categories