2011-10-11 8 views
15

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 @ManyToOneUser 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 @OneToOnereverse 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:

  1. Perché il @ManyToOne all'entità User recuperato con entusiasmo (dato che è stato detto di essere al lavoro pigramente , vedi Making a OneToOne-relation lazy)?
  2. Perché solo la relazione OneToOne all'entità è stata scaricata? È perché l'entità fa riferimento alla colonna PK del PQ come PK stesso (@Id in Tendering), 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).

+0

Forse è solo un bug. Vedi https: // hibernate.onjira.com/browse/HHH-3930, che è simile. –

risposta

2

Ciao io non sono sicuro di JPA, ma per many-to-one e one-to-one mappature dei valori pigri che sono supportati Hibernate sono proxy, no-proxy e false da cui falso è in default. controllare questa parte del DTD

lazy="proxy|no-proxy|false"

e si può controllare questo Link. Penso che questo risponda alla tua prima domanda.

+0

L'impostazione predefinita per 'lazy =" proxy | no-proxy | false "' è proxy, come scritto nel link che hai postato (vedi 12): "lazy (opzionale - default al proxy): per impostazione predefinita, associazioni punto singolo lazy = "no-proxy" specifica che la proprietà deve essere recuperata pigramente quando si accede per la prima volta alla variabile di istanza, che richiede la strumentazione bytecode build-time. lazy = "false" specifica che l'associazione verrà sempre recuperata con impazienza. " – Kawu

0

* La relazione ToOne implica che ci deve essere il bean (proxy) dopo l'inizializzazione dell'oggetto, che attiverà la selezione (lo vedete) non appena vi si accede in alcun modo siete sicuri di non fare nulla con oggetti che potrebbero forzare Caricamento in corso?

0

Hi Kawu vi mostrerà SELECT extra perché si eseguirà seleziona per tutte le entità coinvolte, provare a utilizzare FetchType.LAZY per impostazione predefinita uno-a-molti e in molti casi in modo da utilizzare lo strumento Visualizza JOIN per ottenere risultati.

Spero di aiutare voi o qualcuno che ha bisogno di queste informazioni