2015-01-26 16 views
15

Possiedo un'entità creata di recente da JpaRepository nell'app MVC di Spring. Questa entità si presenta così (molto semplificato):JpaRepository memorizza nella cache l'oggetto appena creato. Come aggiornarlo?

@Entity 
public class Translation { 

    ..... 

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

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

    .... 

} 

e Versione entità:

@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; 

} 

crea un oggetto traduzione come questo

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

dove 11 è una versione che esiste in il database già dall'inizio. Si noti che non imposto valori per name e code di ClientVersionDTO.

Poi Ho un servizio che persiste nuovo oggetto (io uso dozer biblioteca per convertire DTO alle entità)

@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(); 
    } 
} 

Si prega di notare il mio commento "t2.getVersion() restituisce versione in cui sono impostati su 'senza valori codice 'e' nome '"- Mi aspettavo che quando ho recuperato i dati dal database, avrei ottenuto un oggetto Version direttamente dal database con i valori code e name impostati. Tuttavia non sono impostati. Quindi in pratica quello che ottengo come oggetto t2.getVersion() è lo stesso oggetto dell'argomento di input translationDTO.getVersion(). Come possono invalidare nuovamente l'oggetto Version?

UPDATE provato a spostare @Transactional su JpaRepository, ma sempre lo stesso risultato.

+0

Probabilmente vuoi dire "Spring MVC"? È perché hai scritto "Sprint MVC" – AlexR

+0

Sì, grazie. Errori di battitura modificati –

+0

Prova a spostare @Transactional nel tuo repository per un test –

risposta

26

Se si utilizza l'ibernazione, questo è il risultato previsto. Quando si chiama translationRepository.saveAndFlush(translation) e translationRepository.findOne(t.getId()) uno dopo l'altro, viene visualizzata la stessa sessione di Hibernate che mantiene una cache di tutti gli oggetti su cui ha lavorato. Pertanto, la seconda chiamata restituisce semplicemente l'oggetto passato al primo. Non c'è nulla in queste due righe che avrebbe forzato Hibernate a generare una query SELECT sul database per l'entità Version.

Ora, le specifiche JPA hanno un metodo refresh nell'interfaccia EntityManager. Sfortunatamente, Spring Data JPA non espone questo metodo usando l'interfaccia JpaRepository. Se questo metodo fosse disponibile, avresti potuto fare t = translationRepository.saveAndFlush(translation) e poi versionRepository.refresh(t.getVersion()) per forzare il provider JPA a sincronizzare l'entità della versione con il database.

L'implementazione di questo metodo non è difficile. Estendi semplicemente la classe SimpleJpaRepository da Spring Data JPA e implementa il metodo tu stesso. Per ulteriori dettagli, vedere adding custom behaviour to all Spring Data JPA repositories.

Un'alternativa sarebbe caricare l'entità di versione come versionRepository.findOne(version.getId()) prima di impostarla sulla traduzione. Dal momento che puoi inserire l'ID della versione del codice nel tuo codice, le tue versioni sembrano essere statiche. È quindi possibile contrassegnare l'entità Version come @Immutable e @Cacheable (la prima è un'annotazione specifica di Hibernate). In questo modo, versionRepository.findOne(version.getId()) non dovrebbe colpire il database ogni volta che viene chiamato.

+0

grazie, anzi sono anche arrivato alla conclusione e usato il secondo approccio. Btw, la versione non è harcoded, è qui solo per semplicità. –

Problemi correlati