2015-02-26 19 views
11

Mam podmiot, który używam ColumnTransformer dla wiązania i ekstrakt wartości:ColumnTransformer w hibernacji

@Entity 
class BPoint { 
    @Id 
    private Integer id; 

    @ColumnTransformer(read = "astext(shape)", write = "toshape(?)") 
    private Shape shape; 

} 

a dao:

class BPointDao { 
    @Autowired 
    private EntityManager em; 

    @Override 
    public Page<BPoint> findAll(Pageable pageable) { 
     Query q = em.createQuery("from BPoint"); 
     List<BPoint> r = q.getResultList(); 
     int total = em.createQuery("select count(*) from BPoint").getFirstResult(); 
     return new PageImpl(r, pageable, total); 
    } 
    @Override 
    public Integer save(BPoint hbds) { 
     em.persist(hbds); 
     return hbds.getId(); 
    } 
} 

to działa, jednak gdy muszę zrobić jakieś zapytania które wymagają użycia funkcji sql, napotkam pewne problemy, weź ten prawidłowy natywny sql na przykład:

select * from BPoint h where inside(h.shape, 100) = 1; 

Pierwszy próbowałem użyć HQL tak:

Query q = em.createNativeQuery("select astext(shape) from BPoint h where inside(h.shape, ?) = 1"); 

Jednak uważam, że wygenerowany SQL zawiera takie rzeczy jak

...... where inside(astext(h.shape),100).....

Wydaje się, że wartość ColumnTransformer read jest używana w funkcji SQL inside który nie jest oczekiwany.

Więc starałem się używać ojczystego zapytania sql tak:

Query q = em.createNativeQuery("select * from BPoint h where inside(h.shape, ? = 1"); 

Nie SQL mogą być wykonywane, ale wynik nie może być odwzorowane prawidłowo.

Wtedy muszę dodać select fileds manualy tak:

Query q = em.createNativeQuery("select id,astext(shape) from BPoint h where inside(h.shape, ? = 1"); 

Ale co jeśli moja Podmiot dużo fileds powiedzieć, że jest więcej niż 20? A co powiesz na zmianę nazwy kolumn?

Czy istnieje inna metoda spełnienia moich wymagań?

+0

Dlaczego nie spróbować uruchomić natywnego sql i wyniku mapowania przy użyciu 'ResultTransformer' – Amogh

+0

Używam natywnego sql w tej chwili, jednak muszę obliczyć fileds w sql ręcznie, ponieważ tabela zawiera prawie 100+ kolumn. – hguser

+0

Powiedziałeś, że natywny sql może zostać wykonany, ale wynik nie może być poprawnie odwzorowany. piszemy 'ResultTransformer' aby go mapować – Amogh

Odpowiedz

4

Najpierw spróbuj dostarczanie rodzaj powrotu do swojej rodzimej zapytania:

Query q = em.createNativeQuery("select * from BPoint h where inside(h.shape, ? = 1", BPoint.clss); 
List<BPoint> result = q.getResultList(); 

Albo można spróbować zrobić to tak:

Session session = em.unwrap(Session.class); 
List<BPoint> points = (List<BPoint>) session.createSQLQuery("SELECT {h.*} FROM BPoint {h} WHERE inside({h}.shape, ? = 1") 
    .addEntity("h", BPoint.class) 
.list(); 

hibernacji specyficzny API umożliwia mapowanie rodzimych wyników zapytania do podmiotów.

+0

Może nie wyjaśniłem się, nie mogę użyć' select * ..' w natywnej kwerendzie, jeśli tak, hibernacja nie może odwzorować zestawu wyników na obiekt, ponieważ wartość ColumnTransformer nie są używane. – hguser

1

Można utworzyć niestandardowy przechwytywania i „naprawić” SQL wymienić wszystkie „wewnątrz (astext (#ADR)) jako środka (#ADR)

Będziesz musiał zastąpić org.hibernate.Interceptor # onPrepareStatement (String sql) Argument wejściowy zawiera sql, który można zmodyfikować zgodnie z opisem:

+0

Brzmi jak rozwiązanie, ale wydaje się, że zrobię surowy zamiennik łańcucha dla sql w 'onPrepareStatement', który może nie być wiarygodny. – hguser

+0

Tak, to jest ważny problem. Jedyny sposób, w jaki mogę myśleć o robieniu tego w sposób niezawodny i efektywny, polega na rozszerzeniu dialektu i utworzeniu funkcji StandardSQLF oraz nadpisaniu metody renderowania. W tej metodzie otrzymasz reprezentację ciągów znaków i możesz dokonać tej samej modyfikacji tutaj. Sprawdź, czy rzeczywiście można to zrobić dla funkcji "wewnątrz". – codedabbler