2011-08-31 13 views
6

uno scenario di produzione reale. sfondo: 6 tabelle: fondo, conto, periodo, punto di riferimento, holding, posizione.hibernate, Come caricare oggetti complessi nel mondo reale

Fund: The fund information, for example: fund name, total Asset, start time.. etc. 
Account: each fund has an account (one to one) to fund. 
period: time period (for example: 2000-01-01 to 2000-12-31) 
periodweight: at a certain period, the target holding weight. 
holding: IBM, Oracle, GE are stock holdings. 
position: IBM($3000), oracle($2000), GE($5000) 

se ho un nome Comparto: falso, che ha un obiettivo di holding per IBM (30%), Oracle (20%), GE (50%) del periodo (2000-01-01 a 2000-12-31), la posizione actural per il 2000-01-01 è 10%, 10%,% 80% e nel 2000-01-02 è 20%, 20%, 60% sarà rappresentato come questi record in tavolo

Account: id account_Number Fund_id 
     * 1   0001  10 
      2   0002  11 

Fund:  id  name     other properties... 
     * 10   fake fund      xxx 
      11   another fake one    xxx 

period: id  start_time  end_time fund_id 
     * 3  2000-01-01  2000-12-31  10 
      4  2001-01-01  2001-12-31  10 

periodWeight: id  target_weight  holding_id period_id 
       *11  30%     21   3 
       *12  20%     22   3 
       *13  50%     23   3 

holding:  id    name   order  other properties... 
      *21    IBM    1    xxx 
      *22    Oracle   2    xxx 
      *23    GE    3    xxx 

position:  id  Account_id holding_id date    actual_position 
       1   1   11   2000-01-01   10% 
       2   1   12   2000-01-01   10% 
       3   1   13   2000-01-01   80% 
       4   1   11   2000-01-02   20% 
       5   1   12   2000-01-02   20% 
       6   1   13   2000-01-02   60% 

la classe Java sono

Account{ 
    @onetoOne(mappedby="account") 
    Fund f; 

    @oneToMany 
    Set<Position> positions; 
} 

Fund{ 
    @manyToOne 
    Account account; 

    @oneToMany(mappedby="fund") 
    Set<Period> periods; 
} 

Period{ 
    @manyToOne 
    Fund fund; 

    @oneToMany(mappedby="period") 
    Set<PeriodWeight> periodWeights; 
} 

PeriodWeight{ 
    @manyToOne 
    Period period; 

    @ManyToOne 
    Holding holding 
} 

Holding{ 
    @OneToMany(mappedby="holding") 
    Set<PeriodWeight> periodWeights; 

    @OneToMany 
    Set<Position> positions; 
} 

Position{ 
    @manyToOne 
    Account account; 

    @manyToOne 
    Holding holding; 
} 

voglio avere una query: Base d alla data (2000-01-01) e al nome del fondo (fondo falso). Voglio creare un oggetto Fondo, che contiene l'account e il periodo (dal 2000-01-01 al 2000-12-31), e periodo contiene il punto Peso e periodo Peso contiene tenuta, e contiene contiene posizioni per (2000-01-01). quando non esiste tale posizione, ad esempio, interrogo il 2000-01-03 e il fondo falso, voglio avere la struttura, solo la posizione è un insieme vuoto nell'azienda.

questo hql può caricare correttamente la struttura se ci sono dati.

select f from Fund f 
inner join fetch f.account a 
inner join fetch f.period p 
inner join fetch p.periodWeight w 
inner join fetch w.holding h 
inner join fetch h.positions po 
where f.name=:name and :date between p.start_date and p.end_date and :date=po.date and po.account= a 

il problema è quando non ci sono dati nella tabella delle posizioni per quel giorno, restituisce null. Ho bisogno di un sql per darmi la struttura quando non ci sono dati, può caricare tutto tranne la posizione, basta lasciare la posizione impostata vuota.

un'altra domanda è qual è il modo migliore per caricare una struttura così complessa? un hql come questi o carica parte della struttura da una hql quindi dall'altra parte da un'altra hql? beaut in sql, li carichi sempre uno ad uno, prima è il fondo, poi il periodo, poi il peso, poi il mantenimento, poi la posizione ecc. il peso deve essere ordinato in base all'ordine di mantenimento.

select f from Fund f 
inner join fetch f.account a 
inner join fetch f.period p 
inner join fetch p.periodWeight w 
inner join fetch w.holding h 
left join fetch h.positions po with po.account= a and :date=po.date 
where f.name=:name and :date between p.start_date and p.end_date 

è qualcosa di molto vicino, ma questo mi danno errore,

org.hibernate.hql.ast.QuerySyntaxException: with-clause not allowed on fetched associations; use filters 
+0

"il problema è quando non ci sono dati, restituisce null" - Nessun dato dove? nell'associazione delle posizioni? –

+0

sì, quando non ci sono dati nella tabella posiion per la data, ho solo dati per 2000-01-01 e 2000-01-02. quando interrogo il 2000-01-03 e il "fondo falso", restituisce un elenco vuoto di fondi. – Nan

+0

Credo che la mia prima domanda sarebbe, se voglio caricare un oggetto del genere, dovrei romperlo in alcuni mini passi invece di caricare ambiziosamente tutto in una volta? Non riesco a percepire il beneficio dell'ibernazione se uso troppi piccoli passaggi. – Nan

risposta

0

Si dovrebbe essere in grado di compiere questo cambiando:

inner join fetch h.positions p 

a:

left join fetch h.positions p 

e chiamando

query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); 

sull'oggetto query prima di eseguire la query.

+0

Non sono del tutto sicuro su quale query.setResultTransformer (CriteriaSpecification.DISTINCT_ROOT_ENTITY) è valido. la sinistra non si unisce al successo. ancora null – Nan

+0

La tua query sta usando il p alias in due punti: inner join fetch p.period p e inner join fetch h.positions p, devi cambiarne uno, quindi aggiornare la clausola WHERE. –

+0

scusate, è un errore di battitura, l'ho modificato nella domanda e ho inserito quello giusto. Ho anche messo una soluzione molto vicina ma non ancora lì. davvero chiedendo che questo valga un hql così complesso? Sono completamente d'accordo con te per utilizzare il recupero di join sinistro, il problema è con la condizione. mi chiede di usare il filtro e non sono sicuro di come usarlo. a proposito, la tabella delle posizioni è abbastanza grande, non è applicabile per caricare molto prima del filtro, deve essere adattata alla query del database – Nan

2

Questa è una seccante limitazione in HQL, che ho incontrato alcune volte con associazioni basate sul tempo.

ho scoperto che questa è una soluzione a una query HQL contenente fetch e with clausole:

select f from Fund f 
inner join fetch f.account a 
inner join fetch f.period p 
inner join fetch p.periodWeight w 
inner join fetch w.holding h 
left join fetch h.positions po 
where f.name=:name and :date between p.start_date and p.end_date 
and (po is null or (po.account= a and :date=po.date)) 

Il trucco è quello di spostare la clausola with alla clausola where e aggiungere un'opzione per l'oggetto da essere nullo permettendogli di restituire le righe senza una posizione.

+3

Sfortunatamente non è equivalente. Si perdono tutte quelle righe che si aggiungono correttamente ma non corrispondono alla condizione in WHERE. Vedere l'esempio http://pastebin.com/eY8Vw0xG – okocian

Problemi correlati