web-dev-qa-db-fra.com

Pourquoi utiliser l'instance retournée après save () sur le référentiel Spring Data JPA?

Voici le code:

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

JpaRepository du projet Spring Data JPA.

Voici le code de 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());
    }
}

Voici le résultat:

account ID is 0 and for returned account ID is 1

Voici de CrudReporsitory.save () javadoc:

Enregistre une entité donnée. Utilisez l'instance renvoyée pour d'autres opérations car l'opération de sauvegarde peut avoir complètement changé l'instance d'entité.

Voici le code réel pour SimpleJpaRepository de Spring Data JPA:

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

Donc, la question est pourquoi avons-nous besoin d'utiliser l'instance retournée au lieu de l'instance d'origine? (oui, nous devons le faire, sinon nous continuons à travailler avec une instance détachée, mais pourquoi)

La méthode originale EntityManager.persist () renvoie void, donc notre instance est attachée au contexte de persistance. Y a-t-il une magie de proxy lors du passage du compte pour enregistrer dans le référentiel? Est-ce la limitation de l'architecture du projet Spring Data JPA?

55
akazlou

La méthode save(…) de l'interface CrudRepository est censée abstraire simplement le stockage d'une entité, quel que soit son état. Ainsi, elle ne doit pas exposer l'implémentation spécifique au magasin, même si (comme dans le cas JPA), le magasin fait la distinction entre les nouvelles entités à stocker et celles existantes à mettre à jour. C'est pourquoi la méthode est en fait appelée save(…) pas create(…) ou update(…). Nous retournons un résultat de cette méthode pour permettre à l'implémentation du magasin de renvoyer une instance complètement différente comme le fait JPA potentiellement lorsque merge(…) est invoquée.

Donc, généralement, il s'agit plus d'une décision de l'API d'être indulgente (admissible, tolérante) concernant la mise en œuvre réelle et donc la mise en œuvre de la méthode pour JPA comme nous le faisons. Aucune messagerie proxy supplémentaire n'est envoyée aux entités transmises.

60
Oliver Drotbohm

Vous avez manqué la deuxième partie: si l'entité n'est pas nouvelle, merge est appelée. merge copie l'état de son argument dans l'entité attachée avec le même ID et renvoie l'entité attachée. Si l'entité n'est pas nouvelle et que vous n'utilisez pas l'entité renvoyée, vous apporterez des modifications à une entité détachée.

15
JB Nizet