開始行: * キーワード [#hc7c5f18] - JPA - Spring Boot - Kotlin * 目次 [#u3ea0b4d] #contents * したいこと [#ya88d2e3] ひとまず最小でありがちな関連と永続化処理を実装したい。 * エンティティ(単体) [#u812d77a] まずはただIDで識別できる単独の実体。 ** モデル [#dda697ef] @Entity class User( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) *** エンティティにはIDが必要 [#c49b023b] JPAのエンティティはID(プライマリキー)を持つ、のが基本。 *** @Versionを設定 [#a003cc9e] エンティティを楽観ロックするならバージョンを設ける。 ** 永続化処理 [#tf12ecc5] User(name = "山田太郎") .also { entityManager.persist(it) } *** Kotlinで実装する場合デフォルト値の定義が必要 [#l1e04d... Kotlinでエンティティを実装する場合、デフォルト値を定義し... detached entity passed to persist spring jpa * 伝票・明細、集約等(1対多)の関係 [#g2c10fb2] 伝票・明細の関係。伝票単位で明細も含めて一式保存するもの... ** モデル [#x0512dff] Slipを伝票、Detailを明細として。 @Entity class Slip( @OneToMany(mappedBy = "slip", cascade = [CascadeType.A... var details: MutableList<Detail> = emptyList<Detail>()... @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) @Entity class Detail( @ManyToOne @JoinColumn(name = "slip_id", referencedColumnName = "... var slip: Slip? = null, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "" ) *** @OneToManyの設定 [#e05bb408] : mappedBy | 伝票側エンティティが明細側エンティティから何... : cascade | 明細側エンティティにカスケードする永続化オペ... : orphanRemoval | リレーションから削除した明細側エンティ... *** @ManyToOne (@JoinColumn)の設定 [#y0268b0d] : name | 伝票側エンティティを指定する明細側エンティティ上... : referencedColumnName | その外部キーに該当する伝票側エン... *** 伝票側に@Versionを設定 [#tf9cd8f0] 伝票側エンティティに楽観ロック用のバージョンを設ける。 ** 永続化処理 [#y27fae2b] Slip(name = "伝票") .apply { detils.add(Detail(slip = this, name = "明細")... .also { entityManager.persist(it) } *** 明細側エンティティの永続化処理は不要 [#vb186a99] 永続化オペレーションをカスケードするのでpersistするのは伝... * イベントやログ、ジョブ等(多対1)の関係 [#w9a9673b] ある実体に紐づくイベントやログ、ジョブ等の関係。親側エン... ** モデル [#b1701098] Dealを取引、DealEventを取引イベントとして。 @Entity class Deal( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, @Version var version: Long = -1 ) @Entity class DealEvent( @ManyToOne @JoinColumn(name = "foo_id", referencedColumnName = "i... var deal: Deal? = null, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", var raisedAt: LocalDateTime = LocalDateTime.now() ) *** @ManyToOne (@JoinColumn)の設定 [#r7579c63] 伝票・明細、集約等(1対多)の関係、明細側のエンティティ... : name | 親側エンティティを指定する子側エンティティ上の外... : referencedColumnName | その外部キーに該当する伝票側エン... ** 永続化処理 [#xe866e76] entityManager.find(Deal::class.java, dealId) ?.let { DealEvent(deal = it, name = "取引イベント") } ?.also { entityManager.persist(it) } *** managedな親側エンティティが必要 [#f8f37fe5] 子側エンティティにセットする親側エンティティはmanagedであ... * カーソルとスナップショット等(1対1)の関係 [#k9483d82] ある実体を指すカーソルとしての関係。カーソルはすでに存在... ** モデル [#ta5a72c8] @Entity class Cursor( @OneToOne @JoinColumn(name = "details_id", referencedColumnName ... var details: Details? = null, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, @Version var version: Long = -1 ) @Entity class Details( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) *** @OneToOne (@JoinColumn)の設定 [#j5b60b10] イベントやログ、ジョブ等(多対1)の関係、子側のエンティ... : name | ターゲット側エンティティを指定するカーソル側エン... : referencedColumnName | その外部キーに該当するターゲット... ** 永続化処理 [#y24c2c65] Details(name = "スナップショット等") .also { entityManager.persist(it) } .let { Cursor(details = it) } .also { entityManager.persist(it) } *** カーソル側エンティティは子として処理する [#s457845f] ターゲット側のエンティティはmanagedである必要があり、カー... * 任意の関連をもつ(1対0,1)関係 [#nb058329] ユーザーについて固定の記事など、任意の関連をもつ関係。関... ** モデル [#n0f4cbaa] @Entity class User( @OneToOne @JoinTable( name = "user_fixed_post", joinColumns = [JoinColumn(name = "user_id", referenc... inverseJoinColumns = [JoinColumn(name = "post_id", r... ) var fixedPost: Post? = null, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) @Entity class Post( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) *** @OneToOne (@JoinTable, JoinColumn)の設定 [#z0a3b6db] : joinColumns | ユーザー側エンティティを指定する関連テー... : inverseJoinColumns | 記事側エンティティを指定する関連テ... ** 永続化処理 [#m01d54ce] User(name = "ユーザー") .apply { fixedPost = entityManager.find(Post::class.ja... .also { entityManager.persist(it) } *** 記事側エンティティは子のようであるがmanaged [#q8f3dfbe] 伝票・明細、集約等(1対多)の関係のように、記事側エンテ... * 参考 [#sf4400b4] - [[java - How to use spring Repository without @Id? - St... - [[エンティティの状態遷移:http://itdoc.hitachi.co.jp/man... - [[@OneToMany:http://itdoc.hitachi.co.jp/manuals/link/co... - [[OneToMany (Jakarta EE 仕様 API) - Javadoc:https://spr... - [[OneToManyのリストフィールドの削除・更新の仕方 - Qiita... 終了行: * キーワード [#hc7c5f18] - JPA - Spring Boot - Kotlin * 目次 [#u3ea0b4d] #contents * したいこと [#ya88d2e3] ひとまず最小でありがちな関連と永続化処理を実装したい。 * エンティティ(単体) [#u812d77a] まずはただIDで識別できる単独の実体。 ** モデル [#dda697ef] @Entity class User( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) *** エンティティにはIDが必要 [#c49b023b] JPAのエンティティはID(プライマリキー)を持つ、のが基本。 *** @Versionを設定 [#a003cc9e] エンティティを楽観ロックするならバージョンを設ける。 ** 永続化処理 [#tf12ecc5] User(name = "山田太郎") .also { entityManager.persist(it) } *** Kotlinで実装する場合デフォルト値の定義が必要 [#l1e04d... Kotlinでエンティティを実装する場合、デフォルト値を定義し... detached entity passed to persist spring jpa * 伝票・明細、集約等(1対多)の関係 [#g2c10fb2] 伝票・明細の関係。伝票単位で明細も含めて一式保存するもの... ** モデル [#x0512dff] Slipを伝票、Detailを明細として。 @Entity class Slip( @OneToMany(mappedBy = "slip", cascade = [CascadeType.A... var details: MutableList<Detail> = emptyList<Detail>()... @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) @Entity class Detail( @ManyToOne @JoinColumn(name = "slip_id", referencedColumnName = "... var slip: Slip? = null, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "" ) *** @OneToManyの設定 [#e05bb408] : mappedBy | 伝票側エンティティが明細側エンティティから何... : cascade | 明細側エンティティにカスケードする永続化オペ... : orphanRemoval | リレーションから削除した明細側エンティ... *** @ManyToOne (@JoinColumn)の設定 [#y0268b0d] : name | 伝票側エンティティを指定する明細側エンティティ上... : referencedColumnName | その外部キーに該当する伝票側エン... *** 伝票側に@Versionを設定 [#tf9cd8f0] 伝票側エンティティに楽観ロック用のバージョンを設ける。 ** 永続化処理 [#y27fae2b] Slip(name = "伝票") .apply { detils.add(Detail(slip = this, name = "明細")... .also { entityManager.persist(it) } *** 明細側エンティティの永続化処理は不要 [#vb186a99] 永続化オペレーションをカスケードするのでpersistするのは伝... * イベントやログ、ジョブ等(多対1)の関係 [#w9a9673b] ある実体に紐づくイベントやログ、ジョブ等の関係。親側エン... ** モデル [#b1701098] Dealを取引、DealEventを取引イベントとして。 @Entity class Deal( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, @Version var version: Long = -1 ) @Entity class DealEvent( @ManyToOne @JoinColumn(name = "foo_id", referencedColumnName = "i... var deal: Deal? = null, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", var raisedAt: LocalDateTime = LocalDateTime.now() ) *** @ManyToOne (@JoinColumn)の設定 [#r7579c63] 伝票・明細、集約等(1対多)の関係、明細側のエンティティ... : name | 親側エンティティを指定する子側エンティティ上の外... : referencedColumnName | その外部キーに該当する伝票側エン... ** 永続化処理 [#xe866e76] entityManager.find(Deal::class.java, dealId) ?.let { DealEvent(deal = it, name = "取引イベント") } ?.also { entityManager.persist(it) } *** managedな親側エンティティが必要 [#f8f37fe5] 子側エンティティにセットする親側エンティティはmanagedであ... * カーソルとスナップショット等(1対1)の関係 [#k9483d82] ある実体を指すカーソルとしての関係。カーソルはすでに存在... ** モデル [#ta5a72c8] @Entity class Cursor( @OneToOne @JoinColumn(name = "details_id", referencedColumnName ... var details: Details? = null, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, @Version var version: Long = -1 ) @Entity class Details( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) *** @OneToOne (@JoinColumn)の設定 [#j5b60b10] イベントやログ、ジョブ等(多対1)の関係、子側のエンティ... : name | ターゲット側エンティティを指定するカーソル側エン... : referencedColumnName | その外部キーに該当するターゲット... ** 永続化処理 [#y24c2c65] Details(name = "スナップショット等") .also { entityManager.persist(it) } .let { Cursor(details = it) } .also { entityManager.persist(it) } *** カーソル側エンティティは子として処理する [#s457845f] ターゲット側のエンティティはmanagedである必要があり、カー... * 任意の関連をもつ(1対0,1)関係 [#nb058329] ユーザーについて固定の記事など、任意の関連をもつ関係。関... ** モデル [#n0f4cbaa] @Entity class User( @OneToOne @JoinTable( name = "user_fixed_post", joinColumns = [JoinColumn(name = "user_id", referenc... inverseJoinColumns = [JoinColumn(name = "post_id", r... ) var fixedPost: Post? = null, @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) @Entity class Post( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long = -1, var name: String = "", @Version var version: Long = -1 ) *** @OneToOne (@JoinTable, JoinColumn)の設定 [#z0a3b6db] : joinColumns | ユーザー側エンティティを指定する関連テー... : inverseJoinColumns | 記事側エンティティを指定する関連テ... ** 永続化処理 [#m01d54ce] User(name = "ユーザー") .apply { fixedPost = entityManager.find(Post::class.ja... .also { entityManager.persist(it) } *** 記事側エンティティは子のようであるがmanaged [#q8f3dfbe] 伝票・明細、集約等(1対多)の関係のように、記事側エンテ... * 参考 [#sf4400b4] - [[java - How to use spring Repository without @Id? - St... - [[エンティティの状態遷移:http://itdoc.hitachi.co.jp/man... - [[@OneToMany:http://itdoc.hitachi.co.jp/manuals/link/co... - [[OneToMany (Jakarta EE 仕様 API) - Javadoc:https://spr... - [[OneToManyのリストフィールドの削除・更新の仕方 - Qiita... ページ名: