2015年3月18日水曜日

JPA2.1のConverterを使ってEntityの属性の型変換

JPA2.1では、Entityの属性にConverterが設定できて、DBへの保存時や取得時に型変換を行うことができる。

使用方法


Converterクラスの作成

Converterクラスは、javax.persistence.AttributeConverterインタフェースをを実装し、javax.persistence.Converterアノテーションを設定する。
AttributeConverterの総称型には、Entityの属性の型とDBへ挿入する型を指定する。

このコードの例だと、Sex列挙型の値をStringに変換してDBに登録します。
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;

import jpa.entity.Sex;

@Converter
public class SexConverter implements AttributeConverter<Sex, String> {

    @Override
    public String convertToDatabaseColumn(Sex attribute) {
        return attribute.toString();
    }

    @Override
    public Sex convertToEntityAttribute(String dbData) {
        return Sex.valueOf(dbData);
    }
}

Entityの実装

変換対象のカラムにjavax.persistence.Convertアノテーションを指定する。
このアノテーションのconverter属性に、先ほど作成したConverterクラスを指定する。
@Entity
@Table(name = "user_info")
public class User {

    private Long id;

    private Sex sex;

    @Id
    @GeneratedValue
    public Long getId() {
        return id;
    }

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

    @Column
    @Convert(converter = SexConverter.class)
    public Sex getSex() {
        return sex;
    }

    public void setSex(Sex sex) {
        this.sex = sex;
    }
}

実行

以下のコードで、Sex列挙型の項目がDBに文字列で保存されることを確認します。
final User user = new User();
user.setSex(Sex.MALE);
em.persist(user);
DBの値は下の結果のように列挙型の文字列表記になっています。
ID           SEX
---------- --------------------
1            MALE

2015年3月10日火曜日

PostgreSQLでシーケンスを使う

PostgreSQLでのシーケンス作成やシーケンスの操作関数の纏め。

シーケンスの作成

create sequence文を使ってシーケンスを作成する。

全てデフォルトの設定でシーケンスを作成する。(初期値は1、増分値は1、キャッシュはなしなどになる)
create sequence test_seq;

一時的な(今のセッションだけに関連づいた)シーケンスを作成する。
シーケンス作成時に、temp(temporary)を指定すると今のセッションに関連づいた一時的なシーケンスが作られる。(セッションが終了すると、自動的に破棄される。)
既に同名のシーケンスが存在していた場合、一時的なシーケンスが優先されて既にあったシーケンスは見えなくなる。
create temp sequence test_seq;

シーケンスの情報を確認する

シーケンスを検索することで、今の状態が確認できる。
select * from シーケンス名


シーケンスを操作するための関数

nextvalで次の値を取得する。
select nextval('シーケンス名')

currvalで最後にnextvalされた値を取得できる。
select currval('シーケンス名')

setvalで現在の値を変更できる。この例だと、値を999に変更している。
select setval('シーケンス名', 999)


2015年3月8日日曜日

JPA2.1でストアドプロシージャ実行-REF CURSOR編

JPA2.1でストアドプロシージャ実行の続編。
ストアドプロシージャで開いたカーソル(REF CURSOR)をJPA経由で受け取るサンプル。

実行対象のプロシージャ

パラメータは1つで、アウトパラメータでカーソルを返す。
CREATE OR REPLACE PROCEDURE REF_CURSOR_TEST(cur out SYS_REFCURSOR)
AS
BEGIN
    OPEN CUR FOR SELECT *
                 FROM USERS;
END;

実行例

EntityManagercreateStoredProcedureQueryにストアドプロシージャ名を指定してStoredProcedureQueryを生成します。
第2引数には、REF CURSORを受け取るEntityクラスを指定します。(Entity以外でもいいのか?)

executeでストアドプロシージャを実行して、getOutputParameterValueを呼び出してREF CURSORの結果を受け取ります。
ここで受け取ったEntityは管理対象となるので、状態を変更した場合は永続化層に反映される。
final StoredProcedureQuery query = em.createStoredProcedureQuery("REF_CURSOR_TEST", User.class)
         .registerStoredProcedureParameter(1, void.class, ParameterMode.REF_CURSOR);
query.execute();
List users = (List) query.getOutputParameterValue(1);

System.out.println("取得件数 = " + users.size());
users.forEach(user -> {
            System.out.println("id = " + user.getId());
            System.out.println("name = " + user.getName());
            user.setName(user.getName() + ":" + user.getId());
        }
);

実行結果

ストアドプロシージャで開いたカーソルの結果が受け取れていることがわかる。
[EL Fine]: sql: 2015-03-07 23:51:33.88--ClientSession(1620989914)--Connection(108049354)--Thread(Thread[main,5,main])--BEGIN REF_CURSOR_TEST(?); END;
 bind => [=> 1]
取得件数 = 2
id = 1
name = hoge
id = 2
name = fuga