home wiki.fukuchiharuki.me
Menu

キーワード

  • JPA
  • Spring Boot
  • Kotlin

目次

したいこと

ひとまず最小で基本的な関連と永続化処理を実装したい。

エンティティ(単体)

まずはただIDで識別できる単独の実体。

モデル

@Entity
@Table
class Foo(
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  var id: Long = -1,

  var name: String = ""
)

エンティティにはIDが必要

JPAのエンティティはID(プライマリキー)を持つ、のが基本。

永続化処理

val entity = Foo(name = "フー")
entityManager.persist(entity)

Kotlinで実装する場合デフォルト値の定義が必要

Kotlinでエンティティを実装する場合、デフォルト値を定義しておく必要がある。デフォルト値を定義しておかないと、エンティティ永続化時にエラーが発生する。永続化時に値があるかどうかではないことに注意。エラーメッセージからだと原因がなんとも想像つかない。

detached entity passed to persist spring jpa

集約等(1対多)の関係

伝票・明細の関係。伝票単位で一式保存するものとして。

モデル

Fooが伝票、Barが明細。

@Entity
@Table
class Foo(
  @OneToMany(mappedBy = "foo", cascade = [CascadeType.ALL], orphanRemoval = true)
  var barList: MutableList<Bar> = emptyList<Bar>().toMutableList()

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  var id: Long = -1,

  var name: String = "",

  @Version
  var version: Long = -1
)
@Entity
@Table
class Bar(
  @ManyToOne
  @JoinColumn(name = "foo_id", referencedColumnName = "id")
  var foo: Foo? = null,

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  var id: Long = -1,

  var name: String = ""
)

@OneToManyの設定

mappedBy
伝票側エンティティが明細側エンティティから何として関連しているか
cascade
明細側エンティティにカスケードする永続化オペレーション
orphanRemoval
リレーションから削除した明細側エンティティに削除操作を適用する

@ManyToOneの設定

name
伝票側エンティティを指定する明細側エンティティ上の外部キー
referencedColumnName
その外部キーに該当する伝票側エンティティの主キー

伝票側に@Version

伝票側エンティティに楽観ロック用のバージョンを設ける。

永続化処理

val entity = Foo(name = "フー")
  .apply {
    barList.add(
      Bar(foo = this, name = "バー")
    )
  }
entityManager.persist(entity)

明細側エンティティの永続化処理は不要

永続化オペレーションをカスケードするのでpersistするのは伝票側エンティティだけでいい。

ログやイベント等(多対1)の関係

親エンティティに紐づくログやイベント等の関係。親側エンティティの単位で子側エンティティ(ログやイベント等)を一括保存しない。

モデル

@Entity
@Table
class Foo(
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  var id: Long = -1
)
@Entity
@Table
class FooEvent(
  @ManyToOne
  @JoinColumn(name = "foo_id", referencedColumnName = "id")
  var foo: Foo? = null,

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  var id: Long = -1
)

@ManyToOneの設定

1対多(集約等)の関係、明細側のエンティティと同じ。

name
親側エンティティを指定する子側エンティティ上の外部キー
referencedColumnName
その外部キーに該当する伝票側エンティティの主キー

永続化処理

entityManager.find(Foo::class.java, fooId)
  ?.let {
    val entity = FooEvent(foo = it)
    entityManager.persist(entity)
    entity // ^let
  }

managedな親側エンティティが必要

子側エンティティにセットする親側エンティティはmanagedである必要がある(はず)。

カーソル等(1対1)の関係

TBC

任意の関連をもつ(1対0,1)の関係

TBC

参考