2013-03-19 12 views
14

Używam Spring JDBC i nie jestem pewien, jak pracować z wieloma relacjami jeden-do-wielu (lub wiele-do-wielu). W tym przypadku wstawiam repozytorium do jednego z moich zestawów wyników, dzięki czemu mogę odzyskać jego powiązania. Czy to jest sposób na zrobienie tego? To jest złe? Czy są inne lepsze sposoby?Wiele relacji jeden do wielu na wiosnę JDBC

Uwaga: Mam pominięta zastrzyk repozytorium

public class SomeResultSetExtractor implements ResultSetExtractor { 

    public Object extractData(ResultSet rs) throws SQLException, DataAccessException { 
    List result = new LinkedList(); 

    while (rs.next()) { 
     SomeObject object = new SomeObject(rs.getString(1), rs.getLong(2)); 
     result.add(object); 

     List<AnotherObject> otherObjects = anotherRepository.findAllById(object.getId); 
     object.setOtherObjects(otherObjects); 
     // and so on 
    } 

    return result; 

    } 
} 

Okey więc po przeczytaniu Dmytro Polivenok odpowiedź mam zmieniony interfejs RowMapper zamiast i Obecnie używam innych repozytoriów, aby wypełnić wszystkie skojarzenia jak Pokazuję w moim przykładzie. Czy to dobry sposób na robienie tego?

+0

Czy repozytorium rozpoczyna nowe zapytanie SQL? – tkr

Odpowiedz

4

Uważam, że dobrą praktyką dla Spring JDBC i zapytań SQL jest użycie jednego zapytania dla każdej jednostki.

E.g. Zakładamy ten model:

  • Klienta (customerId, nazwisko, wiek, ...)
  • Adres (customerId, typ, ulica, miasto, ...)
  • PaymentOption (customerId, CardNumber, CardType , ...)

  • klienta 1 --- * Adres

  • klienta 1 --- * PaymentOption

Chciałbym zbudować 3 zapytań, 3 DAOS, 3 ResultSetExtractors/RowcallbackHandlers:

  • CustomerDao z readCustomerData (klient lub listy)
  • AddressDao z readAddressForCustomer (klient lub listy)
  • PaymentOptionDao z readPaymentOptionsForCustomer (klient lub listy)

Gdybyś to wypiekł w 1 zapytaniu, musiałbyś zbudować jakąś logikę, aby przywrócić produkt kartatyczny.

  • tj. jeśli klient ma 3 adresy i 2 opcje płatności, zapytanie zwróci 6 wierszy.
  • Jest to dość trudne, jeśli adres lub PaymentOption nie ma własnego klucza podstawowego.

Dla wielu wielu:

  • Klienta * --recommends-- * Produkt

to pewnie zbudować:

  • CustomerDao.readRecommendationsAndProductKeys
  • getDistinctListOfProductKeysFromRecommendations
  • ProductDao.readProducts
  • replaceProductKeysByProductsOnRecommendations

Jak to można ponownie wykorzystać ProductDao.readProducts dla

  • Klienta * --buys-- * Produkt lub
  • produktowe 1 --- * Produkt
+0

Dzięki, to prawie tak samo jak skończyłem. – LuckyLuke

+0

Czy to nie jest tak nieskuteczne, jak podczas kilku rutynowych wycieczek do bazy danych? Załóżmy, że masz obiekt, który ma 3 kolekcje (jedno do wielu relacji) Jeśli potrzebujesz wszystkich danych, zapytanie zwróci 100 obiektów, z kolei wydasz 300 dodatkowych zapytań, aby uzyskać pełne dane, łącznie dla 301 zapytań – greyfox

+0

Pomysł polega na grupowaniu każdego zapytania. Możesz wywołać readCustomerData z 100 identyfikatorami klienta i podzielić wynik na podstawie identyfikatora klienta. Tak więc dla 100 klientów wciąż potrzebujesz tylko 3 zapytań. – tkr

4

Myślę, że twój kod będzie działał, ale tutaj chodzi o użycie ResultSetExtractor, który jest głównie dla samego JDBC, a dla większości przypadków documentation zaleca użycie RowMapper.

Alternatywnym podejściem byłoby posiadanie metody w DAO, która wybiera i mapuje obiekt macierzysty. Następnie dla każdego obiektu należy wywołać inne repozytorium lub metodę prywatną, która wybiera i mapuje obiekty podrzędne, a następnie łączy obiekty potomne z rodzicami na podstawie typu relacji (jednokierunkowe lub dwukierunkowe). Takie podejście może również umożliwiać kontrolowanie, czy chcesz załadować obiekty podrzędne, czy nie.

Na przykład, można sprawdzić aplikację Wiosna PetClinic który ma SimpleJdbcClinic class

Jeśli można użyć innych ram, można rozważyć mybatis, to jest więcej o mapowaniu i pozwala kontrolować swój kod SQL.

+0

Witam, nie jestem pewien, czy dobrze rozumiem twoją odpowiedź. Powiedzmy, że masz zajęcia: Film, Aktor, Gatunek i Komentarz. Chcesz zwrócić obiekt filmowy ze wszystkimi powiązaniami: Jeden film ma wielu aktorów, wiele komentarzy i jeden gatunek. Jak byś to zrobił? – LuckyLuke

+0

Możesz pobrać metodęMovies, która będzie dokonywać wyboru filmów i gatunek oraz zamapować je na obiekty. Następnie dla każdego filmu wywołaj Repository dla aktorów z select/map i Repository dla komentarzy z select/map (lub jeśli aktorzy i komentarze istnieją w twoim kontekście tylko w kategoriach filmów, możesz to zrobić w prywatnych metodach). Po tym ustawi komentarze i autorów do obiektu filmowego –

+0

Okey, więc jeśli zmienię na interfejs wiersza poleceń, to jest lepiej. Co jednak robisz w przypadku wielu do wielu? Jaki jest najlepszy sposób na ich mapowanie? Powiedzmy, że każdy film ma wielu aktorów, a każdy aktor należy do wielu filmów. Masz stół do łączenia? Czy tworzysz metodę na przykład w repozytorium aktorów o nazwie findAllActorsForMovie, które używa tabeli łączenia i tabeli aktorów, aby utworzyć wynik? Tak jak w jednym z wielu? – LuckyLuke