2009-12-10 12 views
5

Chciałbym "dry-run" Hibernate HQL kwerend. To chciałbym wiedzieć, jakie rzeczywiste zapytania SQL Hibernate wykona z danej kwerendy HQL, bez faktycznego wykonywania kwerendy HQL przeciwko rzeczywistej bazie danych.Hibernacja i dry-running zapytania HQL statycznie

Mam dostęp do mapowania hibernacji dla tabel, ciąg kwerendy HQL, dialect dla mojej bazy danych. Mam również dostęp do bazy danych, jeśli jest to potrzebne.

Teraz, w jaki sposób mogę znaleźć wszystkie zapytania SQL Hibernate może generować z mojego HQL bez faktycznego wykonywania kwerendy przeciwko dowolnej bazie danych? Czy są na to jakieś narzędzia?

Należy zauważyć, że wiele zapytań SQL można wygenerować z jednego zapytania HQL, a zestaw generowanych zapytań SQL może się różnić w zależności od zawartości bazy danych.

Nie pytam, jak rejestrować zapytania SQL podczas wykonywania kwerendy HQL.

Edycja: Nie mam nic przeciwko łączeniu się z bazą danych w celu pobrania niektórych metadanych, po prostu nie chcę wykonywać zapytań.

Edycja: wiem również, jakie limity i korekty są stosowane do zapytania. Mam również faktyczne parametry, które będą wiązały się z zapytaniem.

Odpowiedz

5

Krótka odpowiedź brzmi "nie możesz". Długa odpowiedź znajduje się poniżej.

Istnieją dwa podejścia można podjąć:

A) Spójrz w HQLQueryPlan class, szczególnie jego getSqlStrings() method. To nie sprawi, że SQL będzie wymagał dalszego przetwarzania wstępnego, zanim zapytanie zostanie faktycznie wykonane (parametry są powiązane, limity/przesunięcia są stosowane, itd.), Ale może być wystarczająco blisko tego, co chcesz.

Należy pamiętać o tym, że aby zbudować , potrzebna jest rzeczywista instancja HQLQueryPlan, co oznacza, że ​​nie będzie można tego zrobić bez "połączenia z dowolną bazą danych". Możesz jednak użyć bazy danych w pamięci (SqlLite i podobieństwa), a Hibernate automatycznie utworzy dla niej potrzebny schemat.

B) Zacznij od ASTQueryTranslatorFactory i zejście do szaleństwa AST/ANTLR. Teoretycznie możesz zhakować parser, który działałby bez korzystania z metadanych, ale najtrudniej wyobrażam sobie, co próbujesz zrobić, żeby to było tego warte. Być może potrafisz wyjaśnić? Tam ma być lepszym podejściem.

2

Aktualizacja: dla trybu offline, na sucho niektórych HQL, za pomocą HQLQueryPlan bezpośrednio jest dobrym podejściem. Jeśli chcesz przechwycić każde zapytanie w aplikacji, gdy jest uruchomione i nagrać kod SQL, będziesz musiał korzystać z serwerów proxy i refleksji zgodnie z opisem poniżej.

Spójrz na this answer dla zapytań Kryteria.

Dla HQL, jest to ta sama koncepcja - musisz rzucić na klasy implementacji Hibernuj i/lub uzyskać dostęp do prywatnych członków, więc nie jest to obsługiwana metoda, ale będzie działać z wersjami Hibernacji 3.2.3.3. Oto kod, aby uzyskać dostęp do strony internetowej z HQL (zapytanie jest obiekt zwrócony przez session.createQuery (hql_string):

Field f = AbstractQueryImpl.class.getDeclaredField("session"); 
f.setAccessible(true); 
SessionImpl sessionImpl = (SessionImpl) f.get(query); 
Method m = AbstractSessionImpl.class.getDeclaredMethod("getHQLQueryPlan", new Class[] { String.class, boolean.class }); 
m.setAccessible(true); 
HQLQueryPlan plan = (HQLQueryPlan) m.invoke(sessionImpl, new Object[] { query.getQueryString(), Boolean.FALSE }); 
for (int i = 0; i < plan.getSqlStrings().length; ++i) { 
    sql += plan.getSqlStrings()[i]; 
} 

będę owijać wszystko to w try/catch, dzięki czemu można przejść z kwerendy jeśli rejestrowanie nie działa.

Możliwe jest proxy sesji, a następnie proxy kwerendy, aby można było zalogować sql i parametry każdego zapytania (hql, sql, kryteria) przed uruchomieniem, bez kodu, który buduje kwerendy, które muszą zrobić cokolwiek (o ile sesja początkowa jest pobierana z kodu, który kontrolujesz).

+0

Wszystko to kręcenie refleksami jest zupełnie niepotrzebne. 'HQLQueryPlan' ma publiczny konstruktor; wystarczy przesłać fabrykę sesji do 'SessionFactoryImplementor'. – ChssPly76

+0

To prawda, i po ponownym przeczytaniu jego pytania, to prawdopodobnie wszystko, czego potrzebuje. Zajmowałem się sytuacją, w której chcesz przechwytywać HQL/SQL dla każdego zapytania uruchamianego w aplikacji w czasie rzeczywistym - bez konieczności zmiany każdej klasy w aplikacji, która wykonuje zapytanie. Ponieważ nie mam uprawnień do usuwania, dodałem linię, aby wyjaśnić. –

+0

Wystarczająco fair; Jeśli jednak chcesz tylko uchwycić SQL, prawdopodobnie łatwiej (i znacznie bardziej prawdopodobne jest, że przeżyjesz aktualizacje Hibernacji), aby napisać prostego programistę i dołączyć go do 'org.hibernate.SQL' :-) – ChssPly76