2011-12-24 19 views
45

ecco il codice:Perché utilizzare l'istanza restituita dopo save() nel repository JPA di Spring Data?

@Repository 
public interface AccountRepository extends JpaRepository<Account, Long> {} 

JpaRepository dal progetto Primavera dati JPA.

Ecco il codice di test:

public class JpaAccountRepositoryTest extends JpaRepositoryTest { 
    @Inject 
    private AccountRepository accountRepository; 

    @Inject 
    private Account account; 

    @Test 
    @Transactional 
    public void createAccount() { 
     Account returnedAccount = accountRepository.save(account); 

     System.out.printf("account ID is %d and for returned account ID is %d\n", account.getId(), returnedAccount.getId()); 
    } 
} 

Ecco il risultato:

account ID is 0 and for returned account ID is 1 

Qui da CrudReporsitory.save() javadoc:

Salva una data entità. Utilizzare l'istanza restituita per ulteriori operazioni poiché l'operazione di salvataggio potrebbe aver modificato completamente l'istanza dell'entità.

Ecco il codice effettivo per SimpleJpaRepository dalla primavera dati JPA:

@Transactional 
    public T save(T entity) { 
      if (entityInformation.isNew(entity)) { 
        em.persist(entity); 
        return entity; 
      } else { 
        return em.merge(entity); 
      } 
    } 

Quindi, la domanda è perché abbiamo bisogno di utilizzare l'istanza restituita al posto di quello originale? (sì, dobbiamo farlo, altrimenti continuiamo a lavorare con istanza distaccata, ma perché)

Il metodo originale EntityManager.persist() restituisce void, quindi la nostra istanza è associata al contesto di persistenza. Qualche magia proxy si verifica quando si passa un account per salvare nel repository? È la limitazione dell'architettura del progetto JPA di Spring Data?

risposta

48

Il metodo dell'interfaccia CrudRepositorysave(…) dovrebbe abstract semplicemente memorizzare un'entità non importa in quale stato si trova. Così non deve esporre specifica implementazione negozio reale, anche se (come nel APP) caso le differenzia negozio tra le nuove entità da memorizzare e quelle esistenti da aggiornare. Ecco perché il metodo è in realtà chiamato save(…) non create(…) o update(…). Restituiamo un risultato da tale metodo per consentire effettivamente all'implementazione del negozio di restituire un'istanza completamente diversa come potenzialmente fa JPA quando viene richiamato merge(…).

Quindi, in genere, è più una decisione dell'API essere indulgente riguardo l'effettiva implementazione e quindi implementare il metodo per JPA come facciamo noi. Non è stato eseguito alcun massaggio aggiuntivo proxy per le entità passate.

+0

Posso presumere che sia sicuro non utilizzare i risultati di ritorno per le nuove entità? – danidacar

+2

Dove si trova qualche documentazione sullo stato dell'oggetto restituito? Ad esempio, a volte restituisce campi aggiornati (timestamp), a volte i campi non vengono aggiornati dal DB. – mmcrae

9

Hai perso la seconda parte: se l'entità non è nuova, viene chiamato merge. merge copia lo stato dell'argomento nell'entità associata con lo stesso ID e restituisce l'entità associata. Se l'entità non è nuova e non si utilizza l'entità restituita, si apportano modifiche a un'entità distaccata.

+0

Sì, d'accordo. Almeno, in questo caso è compatibile con EntityManager. Sarà meglio rinominare questo metodo per salvareOrMerge()? – akazlou

+0

E i membri transitori dell'oggetto? Nel caso in cui si unisca, ottengo un oggetto nuovo completamente nuovo (che sinceramente non mi interessa) ma perdo tutti i valori transienti del mio oggetto originale. –