web-dev-qa-db-ja.com

保存後にエンティティを更新してフェッチする(JPA / Spring Data / Hibernate)

これらの2つの単純なエンティティSomethingPropertyがあります。 Somethingエンティティは、Propertyと多対1の関係があるため、新しいSomething行を作成するときに、既存のPropertyを割り当てます。

何か:

@Entity
@Table(name = "something")
public class Something implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

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

    @ManyToOne
    private Property property;

    // getters and setters

    @Override
    public String toString() {
        return "Something{" +
            "id=" + getId() +
            ", name='" + getName() + "'" +
            ", owner='" + getOwner() + "'" +
            ", property=" + getProperty() +
            "}";
    }

プロパティ:

@Entity
@Table(name = "property")
public class Property implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

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

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

    @Column(name = "dimension")
    private Integer dimension;

    // getters and setters

    @Override
    public String toString() {
        return "Property{" +
            "id=" + getId() +
            ", shape='" + getShape() + "'" +
            ", color='" + getColor() + "'" +
            ", dimension='" + getDimension() + "'" +
            "}";
    }
}

これはSomethingRepository(春)です:

@SuppressWarnings("unused")
@Repository
public interface SomethingRepository extends JpaRepository<Something,Long> {

}

RESTコントローラとJSONを使用して、新しいSomethingを作成します。

@RestController
@RequestMapping("/api")
public class SomethingResource {

    private final SomethingRepository somethingRepository;

    public SomethingResource(SomethingRepository somethingRepository) {
        this.somethingRepository = somethingRepository;
    }

    @PostMapping("/somethings")
    public Something createSomething(@RequestBody Something something) throws URISyntaxException {
        Something result = somethingRepository.save(something);
        return result;
    }
}

これは入力のJSONです(propertyid 1はデータベースの既存の行です):

{
  "name": "MyName",
  "owner": "MySelf",
  "property": {
    "id": 1
  }

}

問題は、次のとおりです。メソッド.save(something)の後、変数resultには永続化されたエンティティが含まれますが、フィールドpropertyのフィールドがないと、検証されます(これらはnullです)。

出力JSON:

{
  "id": 1,
  "name": "MyName",
  "owner": "MySelf",
  "property": {
    "id": 1,
    "shape": null,
    "color": null,
    "dimension": null
  }
}

保存操作後に検証/返却されることを期待しています。

これを回避するには、RESTコントローラーでEntityManagerを挿入/宣言し、メソッドEntityManager.refresh(something)を呼び出す(または.findOne(something.getId())メソッドを呼び出す必要がある)完全に永続化されたエンティティを持つ):

@RestController
@RequestMapping("/api")
@Transactional
public class SomethingResource {

    private final SomethingRepository somethingRepository;

    private final EntityManager em;

    public SomethingResource(SomethingRepository somethingRepository, EntityManager em) {
        this.somethingRepository = somethingRepository;
        this.em = em;
    }

    @PostMapping("/somethings")
    public Something createSomething(@RequestBody Something something) throws URISyntaxException {
        Something result = somethingRepository.save(something);
        em.refresh(result);
        return result;
    }
}

この回避策により、(正しいJSONを使用して)予想される節約量全体が得られました。

{
  "id": 4,
  "name": "MyName",
  "owner": "MySelf",
  "property": {
    "id": 1,
    "shape": "Rectangle",
    "color": "Red",
    "dimension": 50
  }
}

「完全な」永続エンティティを持つために、JPA、Spring、またはHibernateを使用した自動メソッド/アノテーションはありますか?

すべてのRESTまたはServiceクラスでEntityManagerを宣言することを避けたい、または新しい更新された永続化エンティティが必要になるたびに.findOne(Long)メソッドを呼び出さないようにしたい。

Andreaどうもありがとう

30

Spring Boot JpaRepository:

変更するクエリが永続化コンテキストに含まれるエンティティを変更すると、このコンテキストは古くなります。

最新のレコードでデータベースからエンティティをフェッチするため。

@Modifying(clearAutomatically = true)を使用します

@ModifyingアノテーションにはclearAutomatically属性があり、変更クエリを実行した後に、基になる永続化コンテキストをクリアする必要があるかどうかを定義します。

例:

@Modifying(clearAutomatically = true)
@Query("UPDATE NetworkEntity n SET n.network_status = :network_status WHERE n.network_id = :network_id")
        int expireNetwork(@Param("network_id") Integer network_id,  @Param("network_status") String network_status);
0
Narasimha A