Ho le seguenti entità (solo mappature rilevanti mostrato):JPA/Hibernate: le relazioni @ManyToOne e @OneToOne contrassegnate come FetchType.LAZY e facoltative = false non caricano pigramente su em.find()?
@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Integer id;
@Column
private String name;
@ManyToOne(fetch = FetchType.LAZY) // lazy XToOne
@JoinColumn(name = "user_id", referencedColumnName = "person_id")
private User user;
@OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
private Group group;
@OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
private Tendering tendering;
...
}
Nota le osservazioni di cui sopra: ci sono tre @XToOne
relazioni con altre entità:
utente (una classe SecurityIdentity sub con un semplice ID come PK, a cui fa riferimento PQ rappresenta il proprietario):
@Entity
@Table(name = "Users")
@DiscriminatorValue(value = "user")
public class User extends SecurityIdentity
{
@Column
private String name;
@OneToMany(mappedBy = "user")
private Set<PQ> pqs = new HashSet<PQ>();
...
}
Gruppo (un LSO una classe sub SecurityIdentity con una semplice ID come PK, fa riferimento al PQ per rappresentare un insieme di utenti che possono interagire con quella PQ):
@Entity
@Table(name = "Groups")
@DiscriminatorValue(value = "group")
public class Group extends SecurityIdentity
{
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pq_id", referencedColumnName = "id")
private PQ pq;
...
}
di gara:
@Entity
@Table(name = "Tenderings")
public class Tendering implements Serializable
{
@Id
@Column(name = "pq_id", insertable = false, updatable = false)
private Integer pqId;
@Column(name = "external_code")
private String externalCode;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pq_id", referencedColumnName = "id")
private PQ pq;
...
}
Non essere confusi su gruppi e utenti che condividono gli ID, trattali come semplici ID. Una gara d'appalto è solo un oggetto documento separato (one-to-one).
Come potete vedere ci sono tre @XToOne
relazioni nei confronti del soggetto PQ, che, se nessun tipo di recupero è stato fissato, sarebbe stato caricato con entusiasmo (default JPA). Quindi, per evitare ciò, ho taggato tutte le relazioni @XToOne
come FetchType.LAZY
.
Ora quando si utilizza
em.find(PQ.class, someExistingId);
ho l'uscita Hibernate:
23:53:55,815 INFO [stdout] Hibernate: select pq0_.id as id291_0_, pq0_.description as descript2_291_0_, pq0_.name as name291_0_, pq0_.submission_date as submission4_291_0_, pq0_.user_id as user5_291_0_ from PQs pq0_ where pq0_.id=?
23:53:55,818 INFO [stdout] Hibernate: select user0_.id as id280_0_, user0_1_.identity_type_id as identity2_280_0_, user0_.is_enabled as is1_297_0_, user0_.name as name297_0_, user0_.password as password297_0_, user0_.person_id as person5_297_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
23:53:55,821 INFO [stdout] Hibernate: select group0_.id as id280_0_, group0_1_.identity_type_id as identity2_280_0_, group0_.pq_id as pq2_281_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?
23:53:55,823 INFO [stdout] Hibernate: select tendering0_.pq_id as pq1_296_0_, tendering0_.binary_file as binary2_296_0_, tendering0_.customer_id as customer6_296_0_, tendering0_.description as descript3_296_0_, tendering0_.external_code as external4_296_0_, tendering0_.title as title296_0_ from Tenderings tendering0_ where tendering0_.pq_id=?
I tre SELECT aggiuntivi derivano dai rapporti @XToOne (come descritto in molti posti in rete). La fonte stavo guardando in gran parte è questo:
Making a OneToOne-relation lazy
Come accennato lì, il rapporto @ManyToOne
User user
non dovrebbe essere inverosimile:
@ManyToOne(fetch=FetchType.LAZY)
dovrebbe funzionare bene.
... ecco la relazione dal PQ a utente, ma è inverosimile come si può vedere dalla dichiarazione select user0_.id as id280_0_, ...
...
per le altre due Group group
e Tendering tendering
, entrambi @OneToOne
reverse mapping, le chiavi esterne fanno riferimento al PK (ID) della tabella PQs, risultante nella stessa mappatura nell'entità PQ.
Si noti che tutte e tre le relazioni non sono opzionali: un PQ ha sempre un proprietario (utente), e un PQ è sempre referenziato da un'entità di gara e di gruppo. Non avevo ancora modellato quello in JPA sopra ancora ...
Così, quando si aggiungono optional = false
ai tre rapporti del soggetto PQ:
@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Integer id;
@Column
private String name;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id", referencedColumnName = "person_id")
private User user;
@OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
private Group group;
@OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
private Tendering tendering;
...
}
... ottengo il seguente output Hibernate:
00:47:34,397 INFO [stdout] Hibernate: select pq0_.id as id361_0_, pq0_.description as descript2_361_0_, pq0_.name as name361_0_, pq0_.submission_date as submission4_361_0_, pq0_.user_id as user5_361_0_ from PQs pq0_ where pq0_.id=?
00:47:34,410 INFO [stdout] Hibernate: select user0_.id as id350_0_, user0_1_.identity_type_id as identity2_350_0_, user0_.is_enabled as is1_367_0_, user0_.name as name367_0_, user0_.password as password367_0_, user0_.person_id as person5_367_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
00:47:34,413 INFO [stdout] Hibernate: select group0_.id as id350_0_, group0_1_.identity_type_id as identity2_350_0_, group0_.pq_id as pq2_351_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?
nota, che ho solo giocando con il optional = false
sull'entità PQ, come questo è quello che uso in em.find(...)
. (Se questo non è sufficiente, per favore mi illumini.)
La mia domanda ora è duplice:
- Perché il
@ManyToOne
all'entitàUser
recuperato con entusiasmo (dato che è stato detto di essere al lavoro pigramente , vedi Making a OneToOne-relation lazy)? - Perché solo la relazione
OneToOne
all'entità è stata scaricata? È perché l'entità fa riferimento alla colonna PK del PQ come PK stesso (@Id
inTendering
), che l'entitàGroup
non ha (relazione regolare al PK del PQ)?
Cosa c'è che non va? Come faccio a rendere pigri questi rapporti non facoltativi? (senza strumentazione di codice o altri hack, semplicemente annotazioni ...)
So che la cosa di LAZY è solo un suggerimento per il provider JPA di fare qualcosa sul caricamento pigro o no, ma in questo caso sembra come se qualcos'altro è sbagliato (poiché parte di esso funziona).
PS: sto utilizzando Hibernate 4.0 BETA, la versione fornita con JBoss 7.0.0. Finale con solo annotazioni JPA (le precedenti sono tutte compatibili con JPA 1.0).
Forse è solo un bug. Vedi https: // hibernate.onjira.com/browse/HHH-3930, che è simile. –