2015-01-26 11 views
15

Posiadam JpaRepository uporczywie nowo utworzony podmiot w Spring MVC app. Podmiot ten wygląda następująco (bardzo uproszczony):JpaRepository buforuje nowo utworzony obiekt. Jak to odświeżyć?

@Entity 
public class Translation { 

    ..... 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    private long id; 

    @ManyToOne(fetch = FetchType.LAZY) 
    private Version version; 

    .... 

} 

i wersja podmiot:

@Entity 
public class Version { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "id") 
    private long id; 

    @Column(name = "name") 
    private String name; 

    @Column(name = "version_code") 
    private long code; 

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "version", cascade = {CascadeType.ALL}, orphanRemoval = true) 
    private Set<Translation> translations; 

} 

utworzyć obiekt translacji jak ten

  TranslationDTO t = new TranslationDTO(); 
      t.setText(translationText); 
      ClientVersionDTO version = new ClientVersionDTO(); 
      version.setId(11); 
      t.setVersion(version); 

gdzie 11 to wersja, która istnieje w baza danych już od samego początku. Proszę zauważyć, że nie ustawiam wartości dla name i code z ClientVersionDTO.

Wtedy mam usługę, która utrzymuje się nowy obiekt (używam dozer biblioteki do konwersji Dto podmiotom)

@Service 
@Transactional 
public class TranslationsServiceImpl implements TranslationsService { 
    @Override 
    public Long create(TranslationDTO translationDTO) { 
     Translation translation = translationsConverter.unconvert(translationDTO); 
     Translation t = translationRepository.saveAndFlush(translation); 

     Translation t2 = translationRepository.findOne(t.getId()); 

     // !!!! t2.getVersion() returns version where no values are set to 'code' and 'name' 

     return t2.getId(); 
    } 
} 

Proszę zauważyć mój komentarz „t2.getVersion() zwraca wersję gdzie nie ma wartości są ustawione na ' code 'and' name '"- Spodziewałem się, że po pobraniu danych z bazy danych otrzymam obiekt Version bezpośrednio z bazy danych z ustawionymi wartościami code i name. Jednak nie są one ustawione. Więc zasadniczo to, co otrzymuję jako obiekt t2.getVersion(), jest tym samym obiektem, co w argumencie wejściowym translationDTO.getVersion(). Jak mogę ponownie unieważnić obiekt Version?

AKTUALIZACJA próbował przenieść @Transactional do JpaRepository, ale nadal ten sam wynik.

+0

Czy prawdopodobnie masz na myśli "Spring MVC"? To dlatego, że napisałeś "Sprint MVC" – AlexR

+0

Tak, dziękuję. Zmieniono literówki. –

+0

Spróbuj przenieść swój @Transactional do repozytorium na test –

Odpowiedz

26

Jeśli używasz Hibernate, jest to oczekiwany wynik. Po wywołaniu następujących po sobie translationRepository.saveAndFlush(translation) i translationRepository.findOne(t.getId()) trafiają one w tę samą sesję hibernacji, która utrzymuje pamięć podręczną wszystkich obiektów, nad którymi pracował. Dlatego drugie wywołanie po prostu zwraca obiekt przekazany do pierwszego. W tych dwóch liniach nie ma niczego, co zmusiłoby Hibernate do wystrzelenia zapytania o bazę w bazie danych dla jednostki Version.

Teraz specyfikacja JPA ma metodę refresh na interfejsie EntityManager. Niestety Spring Data JPA nie ujawnia tej metody przy użyciu interfejsu JpaRepository. Jeśli ta metoda była dostępna, można było wykonać t = translationRepository.saveAndFlush(translation), a następnie versionRepository.refresh(t.getVersion()), aby zmusić dostawcę JPA do zsynchronizowania wersji z bazą danych.

Wdrożenie tej metody nie jest trudne. Po prostu rozbuduj klasę SimpleJpaRepository z Spring Data JPA i samodzielnie zaimplementuj metodę. Aby uzyskać szczegółowe informacje, patrz adding custom behaviour to all Spring Data JPA repositories.

Alternatywnym rozwiązaniem byłoby załadowanie encji wersji jako versionRepository.findOne(version.getId()) przed ustawieniem jej w tłumaczeniu. Ponieważ w kodzie można zakodować kod wersji o twardym kodzie, wydaje się, że twoje wersje są statyczne. W związku z tym można oznaczyć jednostkę Version jako @Immutable i @Cacheable (pierwsza z nich to adnotacja specyficzna dla trybu hibernacji). W ten sposób, versionRepository.findOne(version.getId()) nie powinno trafiać do bazy danych za każdym razem, gdy zostanie wywołane.

+0

dzięki, doprawdy też doszedłem do wniosku i zastosował drugie podejście. Btw, wersja nie jest harcoded, jest tutaj tylko dla prostoty. –

Powiązane problemy