読者です 読者をやめる 読者になる 読者になる

DeltaSpike Data Module(使いそうなところだけ)まとめ4

DeltaSpike JPA

Transactions

・・・DeltaSpike JPAも使うつもりだけど、完全に理解できていない。。。
特に指定せずに1トランザクション内で異なるRepositoryの更新ができるなら問題ないけど。。。

とりあえず
「the repository will figure out if a transaction is needed or not」
(リポジトリトランザクションが必要かどうか理解します)
とあるからよろしくやってくれる、、、はず。。。

トランザクションを完全に理解しないのはかなり怖いけど、必要になったらログを見ながら調査予定。

Extensions

リポジトリに独自インターフェースを足して拡張できる。その際、独自インターフェースを実装するimplクラスにDelegateQueryHandlerを付けてね。
という理解。
サンプルではQueryDslライブラリを使えるように拡張している。


・・・QueryDslって何?
QuerydslでJPAが思ったよりも捗る - 水まんじゅう
なるほど、S2JDBCは経験済みだからすぐに理解。でもDeltaSpike Dataが同じような機能を実装してくれている。(後述)


というわけで詳細はスキップ。

Mapping

戻り値をEntityではなくDTOなんかで返せるようにできる。
よくお世話になってくるはず。

public class PersonMapper implements QueryInOutMapper<Person> {
    @Override
    public Object mapResult(Person result) {
        return (変換後オブジェクト);
    }

    @Override
    public Object mapResultList(List<Simple> result) {
        return (変換後オブジェクトのリスト);
    }

    @Override
    public boolean mapsParameter(Object parameter) {
        // ?
    }

    @Override
    public Object mapParameter(Object parameter) {
        // ?
    }
}

QueryInOutMapperをimplementsしてマッピング用のクラスを作り、必要なメソッドを実装する。


・・・いやまて。mapResultList()はListを受けてListを返す?
List件数が膨大になるとOutOfMemoryになるけど、、、iterator的な機能は?

・・・そもそもJPA自体にそういう仕組みが無いのか。ページングをちゃんとしろ、ということなのだろう。
全件CSV出力とかする場合は、1000件づつ取ってくるとか工夫しないといけない。


それはさておき、クラスを作ったらRepositoryで@MappingConfigを使って指定する。

@Repository(forEntity = Person.class)
@MappingConfig(PersonDtoMapper.class)
public interface PersonRepository extends EntityRepository<PersonDto, Long> {}
簡易マッピング(Simple Mappings)

正直、mapsParameter()とmapParameter()は何をするのかよく分からない。
それに実際にやるのはEntity←→DTOの相互変換ぐらいなので、その場合は簡易マッピングを使う。たぶんこちらを使うことになる。

public class PersonMapper extends SimpleQueryInOutMapperBase<Person, PersonDto> {
    @Override
    protected Object getPrimaryKey(PersonDto dto) {
        return dto.getId();
    }

    @Override
    protected PersonDto toDto(Person entity) {
        return parsonDto;
    }

    @Override
    protected Person toEntity(Person entity, PersonDto dto) {
        return entity;
    }
}

SimpleQueryInOutMapperBaseはQueryInOutMapperを実装した抽象クラスで、QueryInOutMapperのよく分からないメソッド達を隠蔽してくれている。
getPrimaryKey()はDTO側でプライマリキーとなるプロパティの値を返すようにする。
toDto()とtoEntity()は読んで字のごとく。

toEntity()の第一引数がEntityになっているが、ソースを見るとEntityManager.find()したEntityを、find()結果が無ければnewのオブジェクトを渡している様子。
必ず引数のEntityを操作して返すこと。(自前でnewとかしない)

JPA Criteria API Support

JPAにCriteriaというAPIがある。が、かなり複雑(みたい)。
(実際に触ったことがないが、色々調べる限り使いたくない。上述のQuerydslなんてものが作られるのが使いにくい証拠)

DeltaSpike DataでもQuerydslのような機能が提供されている。

@Repository(forEntity = Person.class)
public abstract class PersonRepository implements CriteriaSupport<Person> {
    public List<Person> findAdultFamilyMembers(String name, Integer minAge) {
        return criteria()
                .like(Person_.name, "%" + name + "%")
                .gtOrEq(Person_.age, minAge)
                .eq(Person_.validated, Boolean.TRUE)
                .orderDesc(Person_.age)
                .getResultList();
    }
}

「流れるようなインターフェース」というやつでしょうか。多分見て想像がつくSQLが実行される。
これについてはSeasar2(S2JDBC)を使っていたので問題なし。DTOでも返せそう。なのでスキップ。

Auditing

・・・監査?
サンプルでは登録日(Date created)と更新日(Date updated)を更新するような例が載っている。

@PrePersistや@PreUpdate使うのとあまり違いは無い気がする。
(Auditingの方はオブジェクトの作成・更新のタイミングで差し込まれる? でもそこまで厳密なタイムスタンプいらない)

というわけでスキップ。

まとめ終わり。