Java

EclipseLink JPA テーブルをEntityへ読込む際に初期化する

JPAのEntityManagerでレコード読み込み時、Nullだったら空文字に勝手にしたい場合の対処法を記載します。


/**
 * The persistent class for the database table.
 * 
 */
@Entity
@Table(name="sample_table")
@NamedQuery(name="sample_table.findAll", query="SELECT o FROM sample_table o")
public class sample_table implements Serializable {
 private static final long serialVersionUID = 1L;

@EmbeddedId
 private sample_tablePK id;

@Column(name="Id")
 private String id;
 
 @Column(name="col1")
 private String col1;

・・・

・・・

/**
 * PostLoadアノテーションは、EntityManagerでem.setResultListやNamedQuery/NativeQueryなどでレコードアクセスし、
 * Entityへロードする際にフックされる。
 */
 @PostLoad
 private void whenLoadEntity(){
 // System.out.println("================== POST LOAD ====================");
 if(this.col1 == null) this.col1 = "";

・・・(その他レコードロード時の初期化処理を行う)
}

  • @PostLoad
  • private void whenLoadEntity()

上記2行がポイントです。PostLoadアノテーションは、EntityManagerでem.setResultListやNamedQuery/NativeQueryなどでレコードアクセスし、Entityへロードする際にフックされます。

Entityに値が入る前に設定してしまえばNullPointerExceptionの会費になります。但し、Entityを読込のみとして利用する場合に限定する必要がありそうです。(ここら辺はもう少し調べる必要があるかも)

JPA(EclipseLnk)のEntitiyをPostgresqlデータベースから自動生成してValidationまで

JPA(EclipseLnk)のEntitiyをPostgresqlデータベースから自動生成してValidationまでの実装(?)について記載します。

EclipseLinkのJPAはものすごく簡単に便利な機能を提供してくれてます。テーブルの定義がしっかりしていたらその定義のままにEntitiy(Bean)を作成してくれます。

Entity作成手順

Java Persistence API (JPA) を導入します。最初のEclipse自体のセットアップとJPAプロジェクト作成については以下が参考になりました。

DBにあるテーブルへの接続設定

予めDBとテーブルを作成しておきます。JPAパースペクティブを開き、DBへの接続設定を登録します。

ウィザードを使ってEntityを自動作成

プロジェクトを右クリック「JPA TOOL」-「Generate Entities From Table…」を選択するとEntity作成ウィザードが立ち上がります。

「Always generate optional JPA annotations and DDL parameters」にチェックを入れておくとカラム長、ユニークキー、NULL許可などの設定も@column アノテーションに自動付与してくれるので便利です。

@Idはプライマリキーに対して設定されます。

プライマリキーにシーケンスを使っている場合は、@GenaratedValue と @Sequence を使って@Idに自動付与してくれるようにします。

Entityに対してのSQL設定について

SQLはJQLという形式でEntityManager.CreateNamedQueryで定義できたり、SQLそのまま書けるEntityManager.CreateNativeQueryと、動的にソースの中で作成していけるCriteriaBuilderを利用する3つの方法があります。

SQLをそのまま利用したい場合はCreateNativeQueryでよいですし、単純なレコード取得・更新・作成が多ければNamedQueries({NamedQuery(…)[…]})といった形式でEntityに直に書いていった方が楽かもしれません。

また抽出条件が動的に変わるならCriteriaBuilderをお勧めしますが、やはりJOIN等でテーブル関係が複雑になるようだったらデータベース側でViewを作ってしまった方がよいでしょう。

JPAでの挿入・更新・参照

明らかに新規データの時は、EntityManager.persistを使った方がよさそうです。更新挿入(Update or Insert)をする場合は、EntityManager.mergeを利用します。その際に注意点が1つ。

更新時は更新対象のレコードをEntityManager.findや上記NamedQueryなどを利用して、Entityへデータを読み込んでおく必要があります。おそらく、プライマリキーが設定されていたらUpdateして、未設定ならInsertしてくれるんだと思います。あたりまえですが、その際にユニークキーが他のレコードなどと被っているとInsert時にエラーとなったりしてしまいます。

Entityに対してのカラムチェック等・・・Validation

JPA Bean Validation

前述したInsert/Update 時のJPAのEntityに対してValidationをする場合の参考となるソースが上記記載されています。単純にできて便利です。

上級?JPAでメタモデル

後日記載。

eclipseでJPAのメタモデルを自動生成する設定

 

 

EclipseLink JPA『is mapped to a primary key column in the database. Updates are not allowed.』

JPAの開発で『is mapped to a primary key column in the database. Updates are not allowed.』というエラーが出る場合、おそらく原因はいろいろあるのだろうけど、自己解決したのでメモ。

既に存在しているレコードに対して、EntityManager.find で atache したのちプライマリキーを上書きした状態で、merge / flush を行うとなるようです。

find して存在するレコードに更新かける場合はプライマリキーを書き換えないようにしましょう。

2016/4/26追記:

上記記載内容でも解決できずまだエラーログが掃かれていたので調査した結果を記載。EntityManagerを使いまわしでいろんなEntityを入れてmerge/flushしてました。emTransaction.commit / rollback 後は使用しなくなったEntitiyはキャッシュクリアを明示的にしないとずっと保持し続けるようで、これが悪さをしていました。

処理が遅くなるけど、 1テーブル処理が終わったらcommit/rollbackと同時に毎回em.clear();するようにしたらタイトルのエラーが出なくなりました。

またEntityのキャッシュについては、アノテーションによるキャッシュとpersistence.xmlによる設定ができるようです。前者の方がEntity毎に管理できるのでよさそうですね。

キャッシュいついての記事。