web-dev-qa-db-ja.com

Spring DataでJPAエンティティを美しく更新する方法は?

そこで、Spring Dataを使用したJPAに関するさまざまなチュートリアルを見てきましたが、これは多くの場合異なる方法で行われており、正しいアプローチが何であるかはよくわかりません。

次のエンティティがあると仮定します。

package stackoverflowTest.dao;

import javax.persistence.*;

@Entity
@Table(name = "customers")
public class Customer {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private long id;

@Column(name = "name")
private String name;

public Customer(String name) {
    this.name = name;
}

public Customer() {
}

public long getId() {
    return id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}
}

また、サービスレイヤーで取得され、コントローラー/クライアント側に渡されるDTOもあります。

package stackoverflowTest.dto;

public class CustomerDto {

private long id;
private String name;

public CustomerDto(long id, String name) {
    this.id = id;
    this.name = name;
}

public long getId() {
    return id;
}

public void setId(long id) {
    this.id = id;
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}
}

そのため、顧客がwebuiで名前を変更することを望んでいると仮定します。その後、古いIDと新しい名前で更新されたDTOがあるコントローラーアクションがあります。

次に、この更新されたDTOをデータベースに保存する必要があります。

残念ながら、既存の顧客を更新する方法はありません(DBのエントリを削除し、新しい自動生成IDで新しいCusomterを作成する以外は)

しかし、これは現実的ではないので(特に、そのようなエンティティが潜在的に数百の関係を持つ可能性があると考えると)、私の頭には2つの簡単な解決策があります。

  1. customerクラスでIDのセッターを作成します。したがって、IDの設定を許可し、対応するリポジトリを介してCustomerオブジェクトを保存します。

または

  1. idフィールドをコンストラクタに追加し、顧客を更新するたびに、常に古いidで新しいオブジェクトを作成しますが、他のフィールド(この場合は名前のみ)の新しい値を作成します

私の質問は、これを行う一般的なルールがあるかどうかです。私が説明した2つの方法の欠点は何でしょうか?

8
Lukas Makor

@Tanjim Rahmanの答えよりも良いのは、Spring Data JPAを使用してメソッド T getOne(ID id)

_Customer customerToUpdate = customerRepository.getOne(id);
customerToUpdate.setName(customerDto.getName);
customerRepository.save(customerToUpdate);
_

getOne(ID id)参照のみを取得 (プロキシ)オブジェクトであり、DBからそれを取得しないため、より良いです。この参照では、必要なものを設定でき、save()では、期待どおりにSQL UPDATEステートメントを実行します。比較では、@ Tanjim Rahmans answer spring dataのようにfind()を呼び出すと、JPAはSQL SELECTを実行して、DBからエンティティを物理的にフェッチします。

34
Robert Niestroj

シンプルなJPAアップデート.

Customer customer = em.find(id, Customer.class); //Consider em as JPA EntityManager
customer.setName(customerDto.getName);
em.merge(customer);
3
Esty

エンティティではなくDTOを直接操作する必要がある場合は、existing Customerインスタンスを取得し、DTOから更新されたフィールドをそれにマッピングする必要があります。

Customer entity = //load from DB
//map fields from DTO to entity
1
Alan Hay

これは、jpaの質問よりもオブジェクトの初期化の質問です。両方のメソッドが機能し、通常、コンストラクターパラメーターを使用するインスタンス化の前にデータメンバーの値が用意されている場合、インスタンス化後に更新され、セッターが必要です。

1
Amer Qarabsa

Spring Dataでは、IDがある場合は更新クエリを定義するだけです

  @Repository
  public interface CustomerRepository extends JpaRepository<Customer , Long> {

     @Query("update Customer c set c.name = :name WHERE c.id = :customerId")
     void setCustomerName(@Param("customerId") Long id);

  }

一部のソリューションは、Springデータを使用し、代わりにJPAオールドスクールを実行すると主張しています(更新が失われた場合でも)。

0
gorefest