2012-08-06 34 views
8

Mam dwie tabele - jedną zawierającą Adres, a drugą zawierającą Fotografie. Jedynym wspólnym polem między nimi jest PersonID. Zostały one odwzorowane na dwa adresy klas POJO i zdjęcie. Byłem w stanie pobrać szczegóły w tych tabelach, tworząc kryteria i dodając ograniczenia do pól. Jak powinniśmy napisać join na dwóch tabelach. Czy można uzyskać wynik jako dwa obiekty - adres i zdjęcie.Jak połączyć dwie niepowiązane jednostki używając JPA i Hibernate

Chcę wykonać lewą złączkę, aby uzyskać także zapisy osób bez zdjęć. Przeczytałem, że jest to możliwe tylko przy użyciu hql, ale czy można to zrobić również przy użyciu kryteriów?

Odpowiedz

10

Możesz łatwo napisać zapytanie HQL, które zwróci wynik jako dwa obiekty używające Theta Join (jak zauważył Adrian) . Oto przykład:

String queryText = "select address, photo from Address address, Photo photo where address.personID=photo.personId"; 
List<Object[]> rows = session.createQuery(queryText).list(); 

for (Object[] row: rows) { 
    System.out.println(" ------- "); 
    System.out.println("Address object: " + row[0]); 
    System.out.println("Photo object: " + row[1]); 
} 

Jak widać zapytanie zwraca listę tablic Object [] reprezentujących każdy pobrany wiersz. Pierwszy element tej tablicy będzie zawierał jeden obejct i drugi element - inny.

EDIT:

W przypadku lewej przyłączyć Myślę, że trzeba użyć natywną zapytanie SQL (nie zapytań HQL). Oto, jak możesz to zrobić:

String queryText = "select address.*, photo.* from ADDRESS address 
        left join PHOTO photo on (address.person_id=photo.person_id)"; 

List<Object[]> rows = sess.createSQLQuery(queryText) 
          .addEntity("address", Address.class) 
          .addEntity("photo", Photo.class) 
          .list(); 

To powinno działać w twoim przypadku.

+0

Dzięki za przykład, ale możemy zrobić lewe dołączenie ... Próbowałem użyć "Adres lewe dołączyć zdjęcie", ale pojawia się następujący błąd ... "zewnętrznego lub pełnego łączenia musi następować po wyrażeniu ścieżki" – juan

+0

Ok. Edytowałem swoją odpowiedź i dodałem przykład dla lewego połączenia. Myślę, że to powinno działać dla ciebie. – dimas

+0

@dimas czy możemy użyć hql w lewym złączeniu – dom

0

Co szukasz jest

  1. HQL
  2. Dołącz na polach, które nie zostały modelowanych jako relacji
  3. Lewy Dołącz

(W czasie zapytania został pierwszy raz zapytany, a ta odpowiedź została podana) Hibernate wspiera Theta Join, która pozwala na wykonanie 1 & 2. Jednak dla łączenia theta dostępne jest tylko wewnętrzne sprzężenie.

Osobiście poleciłbym modelowanie właściwych relacji, więc wystarczy 1 & 3, który jest dobrze obsługiwany w HQL.

(Inna odpowiedź faktycznie świadczona aktualizacji na nową funkcję hibernacji, który zapewnia taką cechę, że może po prostu patrz)

+0

Zastanawiam się, dlaczego nie głosowano. Odpowiedź jest w rzeczy samej poprawna (nawet zaakceptowana podstawa odpowiedzi na ten temat) i podałem przykład tylko dlatego, że znalezienie dostarczonych kluczowych informacji jest banalne. I wymaganie dotyczące łączenia lewostronnego jest podane później: –

+0

@Ismael Będę je trochę przeformułować, ale nie sądzę, że to, co powiedziałem, jest niekompletne: Nie ma właściwego sposobu użycia HQL do osiągnięcia tego, co jest wymagane przez OP. Theta join jest najbliżej, ale nie robiąc tego, co on, po prostu nie zawracam sobie głowy dawaniem przykładu. –

0

Najlepiej mieć klasę zawierającą te klasy, które chcesz dołączyć mieć je wszystkie razem.

Jeśli jednak dołączasz do tych tabel tylko w niektórych okazjonalnych celach, możesz użyć kryteriów i ręcznie ładować dane z każdej tabeli i umieszczać je razem. (i tak, możesz mieć dane tych tabel osobno, jeśli dla adresu i zdjęcia istnieją dwie oddzielne klasy i tabele)

+0

martin, proszę o trochę więcej. Jak utworzyć klasę dla tego scenariusza? – underdog

+0

Utwórz klasę z atrybutami, które masz w swoim sprzęcie. Ta klasa powinna być związana z tabelą bazy danych z nazwą, która przechowuje relacje między twoimi jednostkami. (Tutaj możemy nazwać je tabelą 'address_photo_rel'). Dlatego, gdy hibernacja tworzy tabele dla twoich klas, tworzona jest również ta tablica dołączeń. _Jeśli tego nie zrobisz, a ponieważ masz relacje między twoimi jednostkami (tutaj 'adres' i' zdjęcie'), hibernacja ostatecznie utworzy tę tabelę, ale nie masz nad tym kontroli, ponieważ nie masz klasy for it._ –

3

Wreszcie po 12 latach zespół Hibernate ma implemented such a feature

Od Hibernate docs:

klauzuli FROM może również zawierać wyraźny związek sprzężeń za pomocą dołączyć słowa kluczowego.Te łączenia mogą być złączami wewnętrznymi lub lewymi zewnętrznymi.

List<Person> persons = entityManager.createQuery(
    "select distinct pr " + 
    "from Person pr " + 
    "join pr.phones ph " + 
    "where ph.type = :phoneType", Person.class) 
.setParameter("phoneType", PhoneType.MOBILE) 
.getResultList(); 


List<Person> persons = entityManager.createQuery(
    "select distinct pr " + 
    "from Person pr " + 
    "left join pr.phones ph " + 
    "where ph is null " + 
    " or ph.type = :phoneType", Person.class) 
.setParameter("phoneType", PhoneType.LAND_LINE) 
.getResultList(); 

Albo można użyć WITH i ON kluczowych. Uwaga na tych

Ważnym wyróżnieniem jest to, że w wygenerowanym SQL warunki z Z/NA klauzuli są częścią klauzuli ON w wygenerowanym SQL, w przeciwieństwie do innych zapytań w tej sekcji gdzie warunki HQL/JPQL są częścią klauzuli WHERE w wygenerowanym kodzie SQL .

Przykład

List<Object[]> personsAndPhones = session.createQuery(
    "select pr.name, ph.number " + 
    "from Person pr " + 
    "left join pr.phones ph with ph.type = :phoneType ") 
.setParameter("phoneType", PhoneType.LAND_LINE) 
.list(); 

Obecnie jestem chętny do wypróbowania nowej funkcji.

3

Jak wyjaśniono w this article, masz dwie opcje:

  1. Ponieważ Hibernate 5.1, można użyć ad-hoc joins niepowiązanych podmiotów.

    Tuple postViewCount = entityManager.createQuery(
        "select p as post, count(pv) as page_views " + 
        "from Post p " + 
        "left join PageView pv on p.slug = pv.slug " + 
        "where p.title = :title " + 
        "group by p", Tuple.class) 
    .setParameter("title", "High-Performance Java Persistence") 
    .getSingleResult(); 
    
  2. Przed Hibernate 5.1, można użyć tylko theta-styl łączy. Jednak łączenie w stylu theta jest równoważne equijoin, dlatego możesz emulować tylko INNER JOINs, a nie OUTER JOINs.

    List<Tuple> postViewCount = entityManager.createQuery(
        "select p as post, count(pv) as page_views " + 
        "from Post p, PageView pv " + 
        "where p.title = :title and " + 
        "  (p.slug = pv.slug) " + 
        "group by p", Tuple.class) 
    .setParameter("title", "Presentations") 
    .getResultList(); 
    

Aby uzyskać więcej informacji, sprawdź this article.

+0

Czy istnieje alternatywa dla poprzedniej wersji. Korzystam z programu hibernate-entitymanager-5.0.9, który daje mi "oczekiwaną ścieżkę dla Join!" błąd –

+0

Możesz użyć sprzężeń w stylu theta. –

Powiązane problemy