I have two entities, Item
and Data
, and a DTO class ItemData
. ItemData
consists of Item
and Data
and has no JPA mapping. To retreive a list of populated ItemDatas, I use a constructor expression in JPQL:
select new my.package.ItemData(i, d)
from Item i, Data d
where i.id = d.itemId
This is what Hibernate is doing: Instead of fetching both the data of Item
and Data
, it gets their IDs first and the data afterwards in n separate select statements. Is there a way to change this behaviour?
Hibernate:
select
item0_.id as col_0_0_,
data1_.id as col_1_0_
from
ITEM item0_,
DATA data1_
Hibernate:
select
item0_.no as no1_0_,
item0_.description as description1_0_,
item0_.organic as bio1_0_,
item0_.gluten as gluten1_0_,
item0_.laktose as laktose1_0_
from
ITEM item0_
where
item0_.id=?
Hibernate:
select
data0_.amount as amount1_3_0_,
data0_.avg as avg3_0_,
data0_.total as total3_0_
from
DATA data0_
where
data0_.id=?
Hibernate:
select
item0_.no as no1_0_,
item0_.description as description1_0_,
item0_.organic as bio1_0_,
item0_.gluten as gluten1_0_,
item0_.laktose as laktose1_0_
from
ITEM item0_
where
item0_.id=?
Hibernate:
select
data0_.amount as amount1_3_0_,
data0_.avg as avg3_0_,
data0_.total as total3_0_
from
DATA data0_
where
data0_.id=?
...and so on...
What about using left join fetch?
I admit I didn't use CTOR expressions, but when I need to fetch a parent entity and its children, I used left join fetch and it always worked like a charm.
I can only assume that since we're dealing here with construction of objects,
Hibernate does not "want" to leave an object "partially constructed" (or let's say - an object in "lazy evaluation state") , and since you did not perform an "eager fetch" using "left join fetch", it performs N+1 fetches:
At first it fetches all the IDs, and then for each relevant ID it performs another fetch.
Read more about left join fetch here (simply look for "left join fetch" at the page)
This is a perfect use case forBlaze-Persistence Entity Views .
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
I suppose your entity model looks something like this?
@Entity
class Item {
@Id Long id;
String description;
@OneToMany(mappedBy = "item")
Data data;
...
}
@Entity
class Data {
@Id Long id;
@ManyToOne Item item;
Long amount;
BigDecimal avg;
...
}
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
@EntityView(Item.class)
public interface ItemData {
@IdMapping
Long getNo();
String getDescription();
@Mapping("SUM(data.amount)")
Long getAmount();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
ItemData a = entityViewManager.find(entityManager, ItemData.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.