67

コードは次のとおりです。

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

Spring Data JPA プロジェクトのJpaRepository 。

テストコードは次のとおりです。

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

結果は次のとおりです。

account ID is 0 and for returned account ID is 1

これは CrudReporitory.save() javadoc からのものです。

特定のエンティティを保存します。保存操作によってエンティティ インスタンスが完全に変更された可能性があるため、返されたインスタンスを以降の操作に使用します。

Spring Data JPA の SimpleJpaRepository の実際のコードは次のとおりです。

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

では、なぜ元のインスタンスではなく、返されたインスタンスを使用する必要があるのでしょうか。(はい、そうしなければなりません。それ以外の場合は、切り離されたインスタンスで作業を続けますが、その理由は)

元の EntityManager.persist() メソッドは void を返すため、インスタンスは永続化コンテキストにアタッチされます。リポジトリに保存するためにアカウントを渡すときに、いくつかのプロキシ マジックが発生しますか? Spring Data JPA プロジェクトのアーキテクチャ制限ですか?

4

2 に答える 2

70

インターフェイスのsave(…)メソッドはCrudRepository、エンティティがどのような状態にあるかに関係なく、エンティティを単純に格納することを抽象化することになっています。したがって、(JPAのように)ストアが格納される新しいエンティティを区別する場合でも、実際のストア固有の実装を公開してはなりません。および既存のものは更新されます。そのため、メソッドは実際にはsave(…)notcreate(…)または。と呼ばれupdate(…)ます。merge(…)そのメソッドから結果を返し、JPAが呼び出されたときに潜在的に行うのとは異なり、ストアの実装が完全に異なるインスタンスを返すことを実際に許可します。

また、実際に不変オブジェクト(つまり、JPAではない)を処理できる永続性実装は、実際の実装で識別子などを入力する必要がある場合、新しいインスタンスを返さなければならない場合がありますつまり、実装がエンティティの状態を消費するだけであると想定するのは一般的に間違っています。

したがって、一般的には、実際の実装に関して寛大(許容可能、許容的)であり、したがって、私たちと同じようにJPAのメソッドを実装することがAPIの決定になります。渡されたエンティティに対して行われる追加のプロキシマッサージはありません。

于 2011-12-26T09:45:07.237 に答える
17

2 番目の部分を見逃しました: エンティティが新しいものでない場合は、mergeが呼び出されます。merge引数の状態を同じ ID を持つ添付エンティティにコピーし、添付エンティティを返します。エンティティが新しくなく、返されたエンティティを使用しない場合は、切り離されたエンティティに変更を加えます。

于 2011-12-24T16:05:40.137 に答える