CrudRepository
の{save}
メソッドが、次のようなデータベース内のエントリを既に検出した場合に更新を行うかどうかを知りたかったのです。
@Repository
public interface ProjectDAO extends CrudRepository<Project, Integer> {}
@Service
public class ProjectServiceImpl {
@Autowired private ProjectDAO pDAO;
public void save(Project p) { pDAO.save(p); } }
したがって、すでに登録されているエントリでそのメソッドを呼び出すと、変更された属性が見つかった場合に更新されますか?
ありがとう。
CrudRepositoryの{save}メソッドがデータベースのエントリを既に見つけた場合に更新を行うかどうかを知りたい
それに関するSpringのドキュメントは正確ではありません:
指定されたエンティティを保存します。保存操作によりエンティティインスタンスが完全に変更された可能性があるため、返されたインスタンスを以降の操作に使用します。
しかし、CrudRepository
インターフェースは、エンティティを更新するための明示的な命名を備えた別のメソッドを提案していないため、CRUDはすべてのCRUD操作(CREATE、READ、UPDATE、DELETE)を行うことが期待されるため、yesであると想定できます。
この仮定は、SimpleJpaRepository
のデフォルトの実装であるCrudRepository
クラスの実装によって確認されます。これは、両方のケースがメソッドによって処理されることを示しています。
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
それで、すでに登録されているエントリでそのメソッドを呼び出すと、変更された属性が見つかった場合に更新されますか?
この場合、マージ操作を実行します。したがって、すべてのフィールドは、マージカスケードおよび読み取り専用オプションの設定方法に従って更新されます。
CrudRepositoryインターフェースのデフォルト実装を見る
/*
* (non-Javadoc)
* @see org.springframework.data.repository.CrudRepository#save(Java.lang.Object)
*/
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
Saveメソッドは、次の2つの状況を管理します。
-個人IDがnullの場合(新しいエンティティが作成される)、saveはpersistメソッドを呼び出します=> insert queryが実行されます。
-個人IDがnullでない場合、saveはmergeを呼び出します。entityManagerFactoryから既存のエンティティを取得し(存在しない場合は2レベルキャッシュから取得し、データベースから取得します)、デタッチされたエンティティと管理対象および最後に、更新クエリを呼び出して、変更をデータベースに伝達します。
データベース内にすでにエントリが見つかった場合、CrudRepositoryの{save}メソッドが更新を行うかどうかを知りたかったのです。
答えは「はい」です。エントリが見つかると更新されます。
Springドキュメントから:ここ https://docs.spring.io/spring-data/jpa/docs/1.5.0.RELEASE/reference/html/jpa.repositories.html ?
エンティティの保存は、CrudRepository.save(…)-Methodを介して実行できます。基盤となるJPA EntityManagerを使用して、指定されたエンティティを永続化またはマージします。エンティティがまだ永続化されていない場合、Spring Data JPAはentityManager.persist(…)-Methodを呼び出してエンティティを保存します。そうでない場合は、entityManager.merge(…)-Methodが呼び出されます。
正確に言うと、save(obj)メソッドは、idが空(したがって挿入を行う)の場合、objをnewレコードとして扱い、objを-として扱います。 existingidが入力されている場合を記録します(したがって、マージを行います)。
これが重要な理由
Projectオブジェクトには、自動生成されたIDと一意でなければならないperson_idが含まれているとします。 Projectオブジェクトを作成し、IDではなくperson_idを入力してから、保存を試みます。 HibernateはIDが空なのでこのレコードを挿入しようとしますが、その人が既にデータベースに存在する場合、重複キー例外が発生します。
処理方法
いずれかのfindByPersonId(id)を実行して、objが既にdbにあるかどうかを確認し、見つかった場合はそこからidを取得します。
または、単に保存を試みて例外をキャッチします。この場合、既にデータベースに含まれていることがわかっており、保存する前にIDを取得して設定する必要があります。
私の場合、エンティティにidプロパティを追加し、このような@Idアノテーションを追加する必要がありました。
@Id
private String id;
この方法では、オブジェクトを取得すると、データベースにエンティティのIDが含まれ、作成ではなく更新操作が実行されます。