Mamy problem z wyborem n + 1 z Hibernate 3.3.Hibernate OneToOne automatyczne pobieranie (rozwiązywanie problemu n + 1)
Dla uproszczenia po prostu wykonam krótki abstrakcyjny przykład.
Załóżmy, że mamy następujące proste ćwiczenia:
class MainEntity {
@Id
public Long id; //we have a table generator create this id
@OneToOne (mappedBy ="main")
public SubEntity subEntity;
}
class SubEntity {
@Id
@Column(name = "mainId") //note that this is the same column as the join column below
public Long mainId; //in order to have the exact same id as the corresponding MainEntity
@OneToOne (fetch = FetchType.LAZY)
@JoinColumn (name = "mainId", insertable = false, updatable = false, nullable = false)
public MainEntity main; //this is used for navigation and queries (" ... subentity.main = :x")
}
Więc jak widać SubEntity
ma związek z MainEntity
która wyraża się przez dwie właściwości, których właściwość mainId
jest jedynym odpowiedzialnym za zarządzanie relację/klucz obcy.
Działa to całkiem dobrze i idealnie pasuje do naszych potrzeb.
Jest jednak jeden problem z niecierpliwym ładowaniem SubEntity
wraz z MainEntity
.
Załóżmy, że mam zapytanie, które zwraca kolekcję MainEntity
. Przy obecnej konfiguracji Hibernacja wyda n + 1 wybiera: samo zapytanie + n wybiera dla każdego SubEntity
.
Oczywiście mógłbym dodać do zapytania zapytanie join fetch
, ale wolałbym, żeby Hibernate zrobił to automatycznie. Dlatego próbowałem dodać @Fetch(FetchMode.JOIN)
, ale to nic nie dało.
Chciałbym również nie ma problemu przy użyciu @Fetch(FetchMode.SUBSELECT)
, co powinno zmniejszyć wybierz oświadczeń 2 - oryginalne zapytanie i select dla jednostek podrzędnych (przynajmniej to, co dzieje się w innym miejscu, z dopiskiem @CollectionOfElements
i @Fetch(FetchMode.SUBSELECT)
).
Więc pytanie brzmi: w jaki sposób mówię do hibernacji automatycznie join pobierać lub korzystać z jednego select w celu niecierpliwością załadować podmioty sub? Czy czegoś brakuje?
Dzięki z góry,
Thomas
PS: Jedna rzecz, która może być problem może być mappedBy = "main"
który nie odnosi rzeczywistą kolumnę id, ale nie mogę go zmienić na mappedBy = "id"
.
Nie wiedziałem o "@ MapsId", dzięki za to. Wypróbuję to. Nawet w przypadku, gdy problem n + 1 nie zostanie rozwiązany, nadal wolałbym takie podejście do naszego obecnego. Tylko pytanie: czy pozwoliłoby mi to po prostu ustawić identyfikator bez odniesienia do "MainEntity"? Mamy przypadki, w których brakuje instancji 'SubEntity' i mamy tylko identyfikator odpowiadającej' MainEntity'. Jeśli to możliwe, wolałbym raczej nie ładować 'MainEntity' tylko dla ustawienia odniesienia. Innymi słowy: co by się stało, gdyby 'id' miał wartość, a' mainEntity' było 'null'? – Thomas
Właśnie zapoznałem się z dokumentacją '@ MapsId', którą połączyłeś i niestety wydaje się, że ta adnotacja została wprowadzona przy użyciu Hibernate 3.5 (a tym samym JPA 2). Jednak obecnie utknęliśmy w JBoss 4.2.3 (który nie obsługuje JPA 2), a zatem nie możemy używać Hibernate 3.5 (pracujemy nad migracją do JBoss 6, ale to zajmie trochę czasu). – Thomas
@Thomas To Odpowiedź na swój pierwszy komentarz. Jak stworzyć 'SubEntity' z tylko identyfikatorem' MainEntity'. Musisz użyć 'EntityManager.getReference', aby uzyskać odniesienie do' MainEntity' bez ładowania go i ustawić na relację 'SubEntiy.main' bez ładowania Main. –