I have a rather simple (probably) question, but somehow struggling to find an answer. How does hibernate map nested entities to java objects? Does it starts its mapping from high-level entities and stops on encountering null-values in ResultSet, or it starts from the lowest-level entities and check all of the hierarchy? The first path seems to be more natural, but yet I didn’t find a concrete answer or any way to configure this
EDIT
By nested entities I suppose something like this:
@Entity public class A { public Long id; public String foo; } @Entity public class B { public Long Id; @OneToOne @JoinColumn(name = "aId") public A bar; }
Where bar field is nested entity for B
One more edit
By ORM-mapping I meant mapping on select query call – so, if table B has no records and we execute any select-query to find entities of B, does Hibernate atempt to find and map entities of A ? Futhermore, if we have
@Entity public class C { public Long Id; @OneToOne @JoinColumn(name = "bId") public B foobar; }
and yet there are no records in table B, some in C and some in A, when we use any find methods for C, does Hibernate attempt to find and map entities of A?
Advertisement
Answer
Hibernate ORM won’t create a proxy for *-to-one association that can be null (@OneToOne(optional=false)
). If the element is missing in the db it will be null when the entity is created. So, using your example, C.foobar
will be null if there is no row on the table B in the db. The same applies to the other *-to-one associations.
If the element is not optional, it might load it lazily and therefore assign a proxy to it.
To expand a bit about your question.
This is a one-to-one association. More in general, what you call nested
is an association in Hibernate ORM. You can find all the details about these types of mapping in the Hibernate ORM documentation.
For your specific example:
@Entity public class A { @Id @Column(name = "aId") public Long id; public String foo; } @Entity public class B { @Id public Long id; @OneToOne @JoinColumn(name = "aId") public A bar; }
Hibernate ORM will create the following tables in Postgres:
create table A (aId int8 not null, foo varchar(255), primary key (aId)) create table B (Id int8 not null, aId int8, primary key (Id)) alter table if exists B add constraint FK3mifipyyn4ao31rn7kftqknuc foreign key (aId) references A
Basically:
- Table A with columns
aid
andfoo
- Table B with columns
id
andaid
- Table B column
aid
has a foreign constraint to Table A columnaid
You can find all the details about one-to-one mapping in the Hibernate ORM documentation.
If you run the HQL query from B
, Hibernate ORM will run the following SQL:
1. select * from B; 2. select * from A a.where a.aid = ?
if the HQL is from C
1. select * from C; 2. select * from B b left outer join A a on b.aId = a.aId where b.id=?;
In both cases, the second query only runs if there are results for the first one.
Keep in mind that this is a basic example and the type of queries executed will change based on the configuration and the mapping of the entities. You can actually tweak this behaviour with small changes to the mapping (Lazy/Eager fetching, optional, using bidirectional associations, …) or the queries. I’m not going through all the possible mappings and you should write your own tests and check what SQL is logged. Hibernate ORM might also skip some queries if some of the entities or the query has been cached.