2011-08-31 12 views
6

prawdziwy scenariusz produkcji. tło: 6 tabel: fundusz, konto, okres, okres masy, gospodarstwo, pozycja.hibernate, Jak załadować złożony obiekt w świecie rzeczywistym

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) 

jeśli mają nazwy funduszu: sztuczny funduszu, który ma na celu gospodarstwa IBM (30%), Oracle (20%), GE (50%) przez okres (2000-01-01 do 2000-12-31), pozycja aktu na 2000-01-01 wynosi 10%, 10%,% 80%, a na 2000-01-02 jest 20%, 20%, 60% będzie reprezentowane jako te zapisy w stół

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% 

Java Class są

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; 
} 

Chcę mieć kwerendy: bazowa d w dacie (2000-01-01) i nazwie funduszu (fałszywy fundusz). Chcę zbudować obiekt funduszu, który zawiera konto i okres (2000-01-01 do 2000-12-31), a okres zawiera okresWaga, a okresWaga zawiera holding, a holding zawiera pozycje dla (2000-01-01). gdy nie ma takiej pozycji, na przykład, pytam 2000-01-03 i fałszywy fundusz, chcę mieć strukturę, tylko pozycja jest pustym zbiorem w gospodarstwie.

Ten hql może poprawnie załadować strukturę, jeśli są dane.

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 

Problem polega na tym, że gdy nie ma danych w tabeli pozycji dla tego dnia, zwracana jest wartość null. Potrzebuję sql, aby dać mi strukturę, gdy nie ma danych, może załadować wszystko z wyjątkiem pozycji, po prostu zostaw puste pole pozycji.

Kolejnym pytaniem jest, jaki jest lepszy sposób na załadowanie tak złożonej struktury? jeden hql jak te lub załadować część struktury przez jeden hql następnie inną część przez inny hql? beause w sql, zawsze ładujesz je jeden po drugim, pierwszy to fundusz, następnie okres, następnie waga, następnie trzymając, następnie stanowisko itp .. waga musi być sortowania w oparciu o zlecenie gospodarstwa.

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 

jest czymś naprawdę blisko, ale to daje mi błąd,

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

"problemem jest brak danych, zwracana jest wartość null" - brak danych gdzie? w stowarzyszeniu stanowisk? –

+0

tak, gdy nie ma danych w tabeli po pozycji dla daty, mam tylko dane dla 2000-01-01 i 2000-01-02. kiedy pytam 2000-01-03 i "fałszywy fundusz", zwraca on pustą listę funduszy. – Nan

+0

Myślę, że moje pierwsze pytanie byłoby, gdybym chciał załadować taki obiekt, czy powinienem go przerwać na kilka mini kroków zamiast ambitnego ładowania wszystkiego na raz? Po prostu nie mogę poczuć korzyści hibernacji, jeśli używam zbyt wielu mini kroków. – Nan

Odpowiedz

0

Powinieneś być w stanie tego dokonać poprzez zmianę:

inner join fetch h.positions p 

do:

left join fetch h.positions p 

i dzwoniąc pod numer

query.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY); 

na obiekcie zapytania przed wykonaniem zapytania.

+0

Nie jestem do końca pewien, do czego służy query.setResultTransformer (CriteriaSpecification.DISTINCT_ROOT_ENTITY). lewy dołączyć nie sukces. still null – Nan

+0

Twoje zapytanie używa p alias w dwóch miejscach: wewnętrzny join fetch f.period p i wewnętrzny join fetch h.positions p, musisz zmienić jeden z nich, a następnie zaktualizować klauzulę WHERE. –

+0

Przepraszam, to literówka, zmieniłem to w pytaniu i wybrałem właściwe. Podaję również bardzo bliskie, ale nie-jeszcze-rozwiązanie. naprawdę zastanawiasz się, czy ten jest wart takiego skomplikowanego hql? Całkowicie zgadzam się z tobą, aby użyć pobierania lewostronnego, problem jest z warunkiem. prosi mnie o użycie filtra i nie wiem, jak go użyć. nawiasem mówiąc, tabela pozycji jest dość duża, nie dotyczy załadunku najpierw dużo, potem filtra, musi być dopasowana do zapytania bazy danych – Nan

2

To denerwujące ograniczenie w HQL, z którym spotkałem się kilka razy z powiązaniami opartymi na czasie.

stwierdziliśmy, że jest to rozwiązanie dla zapytania HQL zawierającej fetch i with punktach:

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)) 

Sztuką jest, aby przenieść się na klauzulę with klauzuli where i dodać opcję dla obiektu do być null pozwalając na zwrócenie wierszy bez pozycji.

+3

Niestety nie jest to odpowiednik. Utracisz wszystkie wiersze, które pomyślnie dołączają, ale nie pasują do warunku w WHERE. Zobacz przykład http://pastebin.com/eY8Vw0xG – okocian

Powiązane problemy