よく質問はほとんどすべてを言います。 JPARepositoryを使ってエンティティを更新するにはどうすればいいですか?
JPARepositoryにはsaveメソッドしかありませんが、実際に作成したのか更新したのかはわかりません。たとえば、データベースのUserに単純なオブジェクトを挿入します。このオブジェクトには、firstnameとlastname、ageの3つのフィールドがあります。
@Entity
public class User {
private String firstname;
private String lastname;
//Setters and getters for age omitted, but they are the same as with firstname and lastname.
private int age;
@Column
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Column
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
private long userId;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public long getUserId(){
return this.userId;
}
public void setUserId(long userId){
this.userId = userId;
}
}
それから私は単に "保存"します。これはこの時点では実際には挿入です。
User user1 = new User();
user1.setFirstname("john"); user1.setLastname("dew");
user1.setAge(16);
userService.saveUser(user1);// This call is actually using the JPARepository: userRepository.save(user);
[OK]をすべて良いです。今、私はこのユーザーを更新したいと思います、彼の年齢を変えると言います。それでは、QueryDSLまたはNamedQueryのどちらでもQueryを使用できます。しかし、spring-data-jpaとJPARepositoryを使用したいだけなのですが、insertの代わりにupdateを実行したいというのはどうすればいいのでしょうか。
具体的には、どのようにしてspring-data-jpaに同じユーザー名と名を持つユーザーがEQUALであり、エンティティを更新することになっていることを伝えますか。等号を上書きすることは機能しませんでした。
ありがとうございました!
エンティティのIDは、プライマリキーによって定義されます。 firstname
とlastname
は主キーの一部ではないため、同じUser
sとfirstname
sを持つlastname
sが等しい場合、JPAに処理するように指示することはできません。異なるuserId
s。
したがって、User
およびfirstname
で識別されるlastname
を更新する場合は、クエリでUser
を見つけてから、オブジェクトの適切なフィールドを変更する必要があります。あなたの見つけた。これらの変更は、トランザクションの終了時にデータベースに自動的にフラッシュされるため、これらの変更を明示的に保存するために何もする必要はありません。
編集:
おそらく、JPAの全体的なセマンティクスについて詳しく説明する必要があります。永続性APIの設計には、主に2つのアプローチがあります。
挿入/更新アプローチ。データベースを変更する必要がある場合、永続化APIのメソッドを明示的に呼び出す必要があります。オブジェクトを挿入するにはinsert
を呼び出し、データベースにオブジェクトの新しい状態を保存するにはupdate
を呼び出します。
作業単位アプローチ。この場合、永続化ライブラリによるオブジェクトのセットmanagedがあります。これらのオブジェクトに加えたすべての変更は、作業ユニットの終了時に(つまり、通常の場合、現在のトランザクションの終了時に)データベースに自動的にフラッシュされます。データベースに新しいレコードを挿入する必要がある場合、対応するオブジェクトmanagedを作成します。 Managedオブジェクトは主キーによって識別されるため、事前定義された主キーmanaged、同じIDのデータベースレコードに関連付けられ、このオブジェクトの状態はそのレコードに自動的に伝播されます。
JPAは後者のアプローチに従います。 Spring Data JPAのsave()
は、プレーンJPAのmerge()
によってサポートされているため、上記のようにエンティティmanagedになります。定義済みのIDを持つオブジェクトでsave()
を呼び出すと、新しいレコードを挿入するのではなく、対応するデータベースレコードが更新され、save()
がcreate()
と呼ばれない理由も説明します。
@axtavtによる答えはspring-data-jpa
ではなくJPA
に焦点を当てているので
クエリを実行してエンティティを更新してから保存するのは効率的ではありません。2つのクエリが必要であり、他のテーブルに結合してfetchType=FetchType.EAGER
を持つコレクションをロードする可能性があるため、クエリが非常に高価になる可能性があります。
Spring-data-jpa
は更新操作をサポートします。
Repository interface.でメソッドを定義し、それに@Query
および@Modifying
のアノテーションを付ける必要があります。
@Modifying
@Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3")
void setUserInfoById(String firstname, String lastname, Integer userId);
@Query
はカスタムクエリを定義するためのもので、@Modifying
はspring-data-jpa
にこのクエリが更新操作であり、executeUpdate()
ではなくexecuteQuery()
が必要であることを伝えるためのものです。
この関数は、JPA関数のsave()で使用することができますが、パラメータとして送信されるオブジェクトにはデータベース内の既存のIDが含まれている必要があります。ただし、既存のIDを持つオブジェクトを送信すると、データベース内ですでに見つかった列が変更されます。
public void updateUser(Userinfos u) {
User userFromDb = userRepository.findById(u.getid());
//crush the variables of the object found
userFromDb.setFirstname("john");
userFromDb.setLastname("dew");
userFromDb.setAge(16);
userRepository.save(userFromDb);
}
他の人がすでに述べたように、save()
自体には作成と更新の両方の操作が含まれています。
save()
メソッドの背後にあるものについての補足を追加したいだけです。
まず、CrudRepository<T,ID>
の拡張/実装階層を見てみましょう、
さて、SimpleJpaRepository<T, ID>
でsave()
の実装をチェックしましょう。
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
ご覧のとおり、まずIDが存在するかどうかを確認します。エンティティが既に存在する場合はmerge(entity)
メソッドによって更新のみが行われ、それ以外の場合はpersist(entity)
メソッドによって新しいレコードが挿入されます。
Spring-data-jpa save()を使用して、@ DtechNetと同じ問題を抱えていました。すべてのsave()が更新ではなく新しいオブジェクトを作成していたということです。これを解決するために、エンティティと関連テーブルにファイルされた "version"を追加しなければなりませんでした。
これは私が問題を解決した方法です:
User inbound = ...
User existing = userRepository.findByFirstname(inbound.getFirstname());
if(existing != null) inbound.setId(existing.getId());
userRepository.save(inbound);
spring dataのsave()
メソッドは、新しいアイテムの追加と既存のアイテムの更新の両方を実行するのに役立ちます。
save()
を呼び出して人生を楽しんでください。
public void updateLaserDataByHumanId(String replacement, String humanId) {
List<LaserData> laserDataByHumanId = laserDataRepository.findByHumanId(humanId);
laserDataByHumanId.stream()
.map(en -> en.setHumanId(replacement))
.collect(Collectors.toList())
.forEach(en -> laserDataRepository.save(en));
}
具体的には、同じユーザー名と名を持つユーザーが実際に同等であり、エンティティを更新することになっていることをspring-data-jpaに伝える方法を教えてください。 equalsのオーバーライドは機能しませんでした。
この特定の目的のために、次のような複合キーを導入できます。
CREATE TABLE IF NOT EXISTS `test`.`user` (
`username` VARCHAR(45) NOT NULL,
`firstname` VARCHAR(45) NOT NULL,
`description` VARCHAR(45) NOT NULL,
PRIMARY KEY (`username`, `firstname`))
マッピング:
@Embeddable
public class UserKey implements Serializable {
protected String username;
protected String firstname;
public UserKey() {}
public UserKey(String username, String firstname) {
this.username = username;
this.firstname = firstname;
}
// equals, hashCode
}
使用方法は次のとおりです。
@Entity
public class UserEntity implements Serializable {
@EmbeddedId
private UserKey primaryKey;
private String description;
//...
}
JpaRepositoryは次のようになります。
public interface UserEntityRepository extends JpaRepository<UserEntity, UserKey>
次に、次を使用できますidiom:ユーザー情報でDTOを受け入れ、名前と名を抽出してUserKeyを作成し、この複合キーでUserEntityを作成してから、すべてをソートするSpring Data save()を呼び出しますあなたのために。