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?
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.
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.