Reputation: 18861
I have a gigantic entity and I'd like to load its subset (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 following JPA query, but 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 it resulted in null as well:
"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 gigantic entity like this then everything works (but I am trying to save some joins):
"SELECT GiganticEntity g WHERE g.id = 1";
Is this achievable with JPA? I am using Hibernate as its implementation.
EDIT: Query actually needs to be LEFT JOIN
, so I need all gigantic entites with baz
-es.
Upvotes: 5
Views: 1173
Reputation: 4643
The @OneToOne
association must be defined as optional = false
. See this question and answer
Yes, I know that sounds crazy, but it's the only way to tell Hibernate to create a Proxy for the associated Entity.
Upvotes: 0
Reputation: 20579
If you don't want to always fetch a OneToOne
(or a ManyToOne
), you should explicitly declare them as lazy (default is eager). Change your code as follows:
@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 query to fetch what you wish:
SELECT GiganticEntity g LEFT JOIN FETCH g.baz WHERE g.id = 1
Upvotes: 0
Reputation: 153780
Since GiganticEntity
has an inverse one-to-one association to a Baz
:
@OneToOne(mappedBy = "giganticEntity")
Baz baz;
It means that Baz has also an association to GiganticEntity
:
@OneToOne
GiganticEntity giganticEntity;
The query can therefore become:
select new package.GiganticEntity(g.id, b)
from Baz b
join b.giganticEntity g
where g.id : id
According to the question requirements changes:
Query actually needs to be LEFT JOIN, so I need all gigantic entites with baz-es.
You can map multiple entities to the same table. You will have the GiganticEntity
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 query goes 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
Upvotes: 2
Reputation: 32517
Why such stragne contruct? I would rather
"SELECT GiganticEntity ge LEFT JOIN FETCH ge.baz WHERE g.id = 1 ";
OR
"SELECT GiganticEntity ge FETCH ALL PROPERTIES WHERE g.id = 1 ";
Upvotes: 0