Hibernate discriminator v OUTER JOIN
Roman Zakutny
roman.zakutny na gmail.com
Čtvrtek Září 17 00:06:04 CEST 2009
Zdravim,
odhliadnuc od toho, ci Vase riesenie nie je zbytocne komplikovane, kedze
nepoznam pozadie celeho problemu, sam som sa pred par mesiacmi taktiez
stretol s absenciou moznosti pridat na ktorykolvek JOIN v dotaze vlastnu
ON podmienku v Criteria API. O moznosti "with" som vedel, avsak HQL som sa
pokial mozno chcel naozaj vyhnut. Na moje prekvapenie ta podpora tam
bohuzial nebola (ak ak bola alebo uz je, budem velmi rad, ze ma niekto z
tohoto omylu vyvedie:) Hibernate vsak ponuka riesenie a ja som ho vyuzil.
Uz si detaily nepamatam, takze neviem presne povedat, aky to ma dopad na
vykon. Nepouzival som ziadne FORMULA ani DISCRIMINATOR features, ale
jednoduchy FILTER COLLECTIONS. Ide o to, ze ak chcete obmedzit nejaku
podmnozinu dat, tak vo vysledku sa tato podmnozina typicky prejavi ako
nejaka Collection v entite (vo Vasom pripade by to bolo Records v Log
entite). Samotny dotaz je bez podmienok a vzhladom na to, ze vysledna
Collection bude typicky LAZY natiahnuta, tak nasledujuce filtrovanie sa
prevadza este v pamati bez pristupu do databazy, co oni oznacuju za velmi
efektivny sposob. Ked potom pristupujete na jednotlive prvky kolekcie, tie
uz splnaju Vami zadane kriteria. Takze taky workaround na ON podmienku...
Doporucujem si pozriet velmi jednoduchy priklad:
http://www.javalobby.org/java/forums/t43955.html
Na moj problem som si s tym bez problemov vystacil a nemusel som pouzit
HQL. Chapem, ze pre komplikovane podmienky napriec roznymi entitami v
dotaze toto pouzitie nemusi byt jednoduche, ba dokonca nemozne...
S pozdravom Roman.
On Wed, 16 Sep 2009 22:44:30 +0200, Lukas Barton <lukas na cnawr.cz> wrote:
> Proc proste nenapisete:
> select Record1 from Record1 where not exists(select Log.id from Log
> where Log.id = Record1.id and Log.type = "TL")
>
> Nemusite nic znasilnovat a je to i srozumitelnejsi.
>
> On 9/16/09, Rastislav Siekel <siekel na prosoft.sk> wrote:
>> Ahojte,
>>
>> nevedel by niekto poradiť ako dostanem v Hibernate podmienku do klauzuly
>> ON pre outer join?
>>
>> Mám tabuľky záznamov - napr. RECORD1, RECORD2, ... a jednu tabuľku logov
>> - napr. LOG , kde si poznačím, ktoré záznamy a akého typu už boli
>> spracované.
>> Na úvod hľadám záznamy, ktoré ešte neboli vôbec spracované a preto v
>> tabuľke LOG nie sú. Typ záznamu hľadám napr. 'TL' a tie sú v tabuľke
>> RECORD1.
>>
>>
>> Potrebujem vygenerovať asi takýto SELECT:
>> *select RECORD1.*
>> from LOG
>> right outer join RECORD1 on (**LOG.TYPE= 'TL' and
>> **RECORD1.ID=**LOG.ID**)
>> where LOG.ID is null
>> *
>>
>> Hibernate som najprv znásilnil cez <formula>, aby mi to generoval, asi
>> takto:
>> *<class name="log" table="LOG" >
>> <id name=... />
>>
>> <property name="record1_Id" column="RECORD1_ID" type=... />
>>
>> <many-to-one name="record1" column="RECORD1_ID" class=... />
>> <formula>LOG_TYPE='TL' and RECORD1_ID</formula>
>> </many-to-one>
>>
>> ...
>> </class>
>>
>> *Toto fungovalo a všetko bolo v poriadku. Potom však prišla požiadavka
>> čítať záznamy z LOG-u a pre takéto mapovanie sa tá <formula> ocitla v
>> SELECT liste, čo samozrejme spôsobilo neplatné SQL.
>>
>> Pokúšal som sa uvedené mapovanie zmeniť pomocou DISCRIMINATOR-a a nového
>> potomka triedy LOG (napr. logExt) nejako takto:
>> *<class name="log" table="LOG" >
>> <id name=... />
>>
>> <discriminator column="LOG_TYPE" type="string" length="2" />
>>
>> <property name="record1_Id" column="RECORD1_ID" type=... />
>>
>> <subclass name="logExt" discriminator-value="TL">
>> ** <many-to-one name="record1" column="RECORD1_ID" class=...
>> />
>> ** </subclass>
>>
>> ...
>> </class>
>> *
>> Čo však vygenerovalo takýto SQL:
>> *select RECORD.ID, ...
>> from LOG
>> right outer join RECORD on LOG.ID=RECORD.ID
>> where LOG.ID is null ** and **LOG.TYPE= 'TL'
>>
>> *Čiže podmienka *LOG.TYPE= 'TL'* sa ocitla vo WHERE a nie v ON klauzule,
>> čo má samozrejme fatálny vplyv na výsledok, pretože ak LOG je null, tak
>> podmienka na LOG.TYPE je vždy FALSE a vráti sa prázdna množina.
>>
>> Priateľ google napovedal, že Gavin 26.8.2003 tvrdil, že mapovanie
>> *<discriminator>* s atribútom *force="true"* prinesie tento
>> diskriminator do ON klauzuly - viď
>> https://forum.hibernate.org/viewtopic.php?f=1&t=934203&view=next
>> ale mne sa to takto nechová.
>>
>>
>> Teraz mi ostali asi 2 možnosti riešenia, ale ani jedna sa mi nepozdáva.
>>
>> 1. Vytvoriť dve mapovania (trebárs ako predok a potomok), kde do
>> potomka dám uvedené hack-y typu <formula> a keď budem chcieť čítať
>> záznamy z LOG-u, budem čítať predka.
>> 2. Použiť v HQL klauzulu WITH, ktorá dáva podmienku do ON klauzuly,
>> ale musel by som zmeniť smer mapovania - RECORD by mal namapovaný
>> LOG, čo je logicky zle, lebo entita RECORD nemá nič vedieť o tom,
>> že si ju niekto loguje.
>>
>>
>> Neviete niekto ešte inú možnosť?
>>
>> Rastislav "Bedo" Siekel
>>
>> P.S. Hibernate 3.2.1.ga voči Oracle 10.
Další informace o konferenci Konference