web-dev-qa-db-ger.com

Warum sollte die zurückgegebene Instanz nach save () im JPA-Repository von Spring Data verwendet werden?

Hier ist der Code:

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

JpaRepository aus dem Spring Data JPA-Projekt.

Hier ist der Testcode:

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

Hier ist das Ergebnis:

account ID is 0 and for returned account ID is 1

Hier ist von CrudReporsitory.save () javadoc:

Speichert eine bestimmte Entität. Verwenden Sie die zurückgegebene Instanz für weitere Operationen, da die Entitätsinstanz durch die Sicherungsoperation möglicherweise vollständig geändert wurde.

Hier ist der aktuelle Code für SimpleJpaRepository von Spring Data JPA:

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

Die Frage ist also, warum wir die zurückgegebene Instanz anstelle der ursprünglichen Instanz verwenden müssen. (Ja, wir müssen es tun, andernfalls arbeiten wir mit der getrennten Instanz weiter, aber warum?)

Die ursprüngliche EntityManager.persist () -Methode gibt void zurück, sodass unsere Instanz an den Persistenzkontext angehängt ist. Tritt Proxy-Magie auf, während ein Konto an das Repository übergeben wird? Liegt es an der Architekturbeschränkung des Spring Data JPA-Projekts?

55
akazlou

Die save(…) -Methode der CrudRepository -Schnittstelle soll das einfache Speichern einer Entität abstrahieren, egal in welchem ​​Zustand sie sich befindet. Daher darf sie die tatsächliche speicherspezifische Implementierung nicht offenlegen, auch wenn (wie in In dem JPA-Fall unterscheidet der Speicher zwischen neuen zu speichernden Entitäten und bestehenden zu aktualisierenden Entitäten. Deshalb heißt die Methode tatsächlich save(…) nicht create(…) oder update(…). Wir geben ein Ergebnis dieser Methode zurück, damit die Speicherimplementierung tatsächlich eine völlig andere Instanz zurückgeben kann, als dies JPA möglicherweise tut, wenn merge(…) aufgerufen wird.

Im Allgemeinen ist es also eher eine API-Entscheidung, in Bezug auf die tatsächliche Implementierung nachsichtig (zulässig, tolerant) zu sein und die Methode für JPA so wie wir zu implementieren. Es wird kein zusätzliches Proxy-Messaging für die übergebenen Entitäten durchgeführt.

60
Oliver Drotbohm

Sie haben den zweiten Teil verpasst: Wenn die Entität nicht neu ist, wird merge aufgerufen. merge kopiert den Status seines Arguments in die angehängte Entität mit derselben ID und gibt die angehängte Entität zurück. Wenn die Entität nicht neu ist und Sie die zurückgegebene Entität nicht verwenden, nehmen Sie Änderungen an einer getrennten Entität vor.

15
JB Nizet