2011-12-24 25 views
45

Oto kod:Dlaczego warto używać zwróconej instancji po save() w repozytorium JPA Spring Data?

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

JpaRepository od projektu Wiosna danych WZP.

Oto kod badania:

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

Oto wynik:

account ID is 0 and for returned account ID is 1 

Oto z CrudReporsitory.save() javadoc:

Zapisuje danego podmiotu. Użyj zwróconej instancji do dalszych operacji, ponieważ operacja składowania mogła całkowicie zmienić instancję jednostki.

Oto kod rzeczywisty dla SimpleJpaRepository od wiosny Danych JPA:

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

Więc pytanie jest dlaczego musimy użyć wracającą instancji zamiast pierwotnego? (tak, musimy to zrobić, w przeciwnym razie kontynuujemy pracę z odłączoną instancją, ale dlaczego)

Oryginalna metoda EntityManager.persist() zwraca pustkę, więc nasza instancja jest dołączona do kontekstu utrwalania. Czy podczas przechodzenia przez konto do zapisania w repozytorium pojawia się jakaś magia proxy? Czy jest to ograniczenie architektury projektu Spring Data JPA?

Odpowiedz

48

save(…) metoda interfejsu CrudRepository ma streszczenie po prostu przechowywania podmiot bez względu na to, co państwo to jest w. Dlatego nie należy wystawiać konkretnej implementacji rzeczywisty sklepu, nawet jeśli (jak w JPA) przypadku rozróżniać produkty w sklepach między nowymi obiektami, które mają być przechowywane, a tymi, które mają być aktualizowane. Właśnie dlatego metoda ta jest faktycznie nazywana save(…) nie create(…) lub update(…). Zwracamy wynik tej metody, aby faktycznie umożliwić implementacji sklepu zwrócić zupełnie inną instancję, ponieważ JPA potencjalnie robi to po wywołaniu merge(…).

Ogólnie rzecz biorąc, decyzja API jest łagodniejsza, jeśli chodzi o faktyczną implementację i tym samym wdrożenie metody JPA, tak jak my. Nie ma dodatkowego masowania proxy wykonanych przekazanych jednostek.

+0

Czy mogę założyć, że nie można użyć wyników zwrotu dla nowych podmiotów? – danidacar

+2

Gdzie jest dokumentacja dotycząca stanu zwróconego obiektu? Oznacza to, że czasami zwraca zaktualizowane pola (znaczniki czasu), czasami pola nie są aktualizowane z bazy danych. – mmcrae

9

Tęskniłeś za drugą częścią: jeśli jednostka nie jest nowa, wywoływana jest nazwa merge. merge kopiuje stan argumentu do dołączonej jednostki o tym samym identyfikatorze i zwraca dołączoną jednostkę. Jeśli jednostka nie jest nowa i nie używasz zwróconego elementu, wprowadzisz modyfikacje do odłączonego obiektu.

+0

Tak, zgadzam się. Przynajmniej w tym przypadku jest to zgodne z EntityManager. Czy lepiej będzie zmienić nazwę tej metody na saveOrMerge()? – akazlou

+0

Co ze przejściowymi elementami obiektu? W przypadku, gdy się scala, otrzymuję zupełnie nowy Obiekt Rzeczywisty (na co mi naprawdę nie zależy), ale tracę wszystkie wartości przejściowe mojego oryginalnego obiektu. –