JPA: selecting a subset of an object does not load @OneToOne property
I have a giant object and I would like to load a subset of it (ID and baz property):
@Entity
public class GiganticEntity {
@Id Long id;
@OneToOne(mappedBy = "giganticEntity")
Foo foo;
@OneToOne(mappedBy = "giganticEntity")
Bar bar;
@OneToOne(mappedBy = "giganticEntity")
Baz baz;
// default constructor + getters/setters
public GiganticEntity(Long id, Baz baz) {
this.id = id;
this.baz = baz;
}
}
I tried using the following JPA query, but the baz property will be null:
"SELECT new package.GiganticEntity(ge.id, ge.baz) " +
"FROM GiganticEntity ge WHERE ge.id = 1";
I tried adding an explicit join, but that also resulted in a null value:
"SELECT new package.GiganticEntity(ge.id, b) FROM GiganticEntity ge " +
"LEFT JOIN ge.baz as b " +
"WHERE ge.id = 1";
If I only select my giant object like this, then everything works (but I'm trying to keep some connections):
"SELECT GiganticEntity g WHERE g.id = 1";
Is this possible with JPA? I am using Hibernate as my implementation.
EDIT : Actually the request should be LEFT JOIN
, so I need all the giant permissions with baz
-es.
Since it GiganticEntity
has a one-to-one feedback with Baz
:
@OneToOne(mappedBy = "giganticEntity")
Baz baz;
This means that Baz also has a relationship with GiganticEntity
:
@OneToOne
GiganticEntity giganticEntity;
So the request could be as follows:
select new package.GiganticEntity(g.id, b)
from Baz b
join b.giganticEntity g
where g.id : id
Edit
According to the requirements for the requirements:
Actually the request should be a LEFT JOIN, so I need all the giant base ideas.
You can map multiple objects in one table. You will have GiganticEntity
one containing all associations and several entity views:
@Entity
@Table(name="GiganticEntity")
@Immutable
public class GignaticBazViewEntity {
@Id Long id;
@OneToOne(mappedBy = "bar")
Bar bar;
@OneToOne(mappedBy = "baz")
Baz baz;
public GiganticEntity(Long id, Bar bar, Baz baz) {
this.id = id;
this.bar = bar;
this.baz = baz;
}
}
The request looks like this:
select g
from GignaticBazViewEntity g
left join fetch g.bar
left join fetch g.baz
where g.id : id
or
select g
from GignaticBazViewEntity g
FETCH ALL PROPERTIES
where g.id : id
Why such a constructive approach? I would prefer
"SELECT GiganticEntity ge LEFT JOIN FETCH ge.baz WHERE g.id = 1 ";
OR
"SELECT GiganticEntity ge FETCH ALL PROPERTIES WHERE g.id = 1 ";
If you don't want to always fetch OneToOne
(or a ManyToOne
), you must explicitly declare them lazy (the default is impatient). Change your code like this:
@Entity
public class GiganticEntity {
@Id Long id;
@OneToOne(mappedBy = "giganticEntity", fetch = FetchType.LAZY)
Foo foo;
@OneToOne(mappedBy = "giganticEntity", fetch = FetchType.LAZY)
Bar bar;
@OneToOne(mappedBy = "giganticEntity", fetch = FetchType.LAZY)
Baz baz;
// default constructor + getters/setters
}
Then write your request to get what you want:
SELECT GiganticEntity g LEFT JOIN FETCH g.baz WHERE g.id = 1
The link @OneToOne
should be defined as optional = false
. See this question and answer
Yes, I know it sounds crazy, but this is the only way to tell Hibernate to create a proxy for the associated Entity.