2017年度 Java 永続化フレームワークについての考察(9) Speedment

#前ポスト
- [2017年度 Java 永続化フレームワークについての考察(1)](http://qiita.com/shiroma_yuki/items/8d434862bba072bff264)
- [2017年度 Java 永続化フレームワークについての考察(2) Doma2](http://qiita.com/shiroma_yuki/items/d0e3b319626f4278fc6f)
- [2017年度 Java 永続化フレームワークについての推測(3) Reladomo](https://qiita.com/shiroma_yuki/items/1e3d83202afa6cf5dbef)
- [2017年度 Java 永続化フレームワークについての考察(4) jOOQ](https://qiita.com/shiroma_yuki/items/1f64cac07afc745579a5)
- [2017年度 Java 永続化フレームワークについての考察(5) Iciql](https://qiita.com/shiroma_yuki/items/42e2cf97076c964e8629)
- [2017年度 Java 永続化フレームワークについての考察(6) Ebean](https://qiita.com/shiroma_yuki/items/283c89ad13f90e25c0d5)
- [2017年度 Java 永続化フレームワークについての考察(7) EclipseLink](https://qiita.com/shiroma_yuki/items/5eca0c61d4a7e7c54886)
- [2017年度 Java 永続化フレームワークについての考察(8) Hibernate5](https://qiita.com/shiroma_yuki/items/960905c5a8437bc1f09e)

#前置き
隙間時間を利用して書いているので精度の甘い箇所があれば、ご指摘いただけると幸いです。
まずEOLであるものは除外。
有償の機能については検討対象に含むが、実際に使用はしません、懐の問題で。
「まぁ、たぶん明記されてなくてもPostgreならいけるだろ」ぐらいの間抜けな理由で使用DBはPostgreに固定。

#環境
- PostgreSQL 9.6.3
- [speedment 3.0.18](https://github.com/speedment/speedment)
- Java 64bit 8u144

#テーブル構成
![employeeテーブルからpostテーブルにID紐づけ](https://qiita-image-store.s3.amazonaws.com/0/48666/ec265f75-ad54-4f56-a5f8-2b460723047a.png)


#対応範囲
|ORM|Transaction|Data Model|DSL|
|:-:|:---------:|:--------:|:-:|
|○|○|×|○|
○:対応
×:非対応

#所感
- maven環境が整ってないと手の出しようがなかったけれど、環境が整ったらさっくりできた
- Stream操作がDB操作と一体化しているので慣れが必要
- 生成されるコードが大分ある、どれがどれかと把握するのに少し手間取るぐらい
- 公式に「JOIN:flatMap()」と記載があるのだけれど、[Java Magazinでいわく、LazyFetchでPreFetchは実装予定とのこと](http://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-MJ17-FluentORM.pdf)

#サンプル
##単テーブル検索
###全件検索
```Main.java
OrmSpeedmentApplication app = new OrmSpeedmentApplicationBuilder().withPassword("pass").build();
app.getOrThrow(EmployeeManager.class).stream().forEach(Main::sysout);
app.stop();
```
```Main#sysout(Employee).java
public static void sysout(Employee e) {
    System.out.format("%1s: %2s, %3s, %4s\n", e.getId(), e.getFirstName(), e.getMiddleName(), e.getLastName());
}
```

###主キー検索
```Main.java
app.getOrThrow(EmployeeManager.class).stream()
    .filter(Employee.ID.equal(BigDecimal.ONE))
    .forEach(Main::sysout);
```

##テーブル結合
```Main.java
app.getOrThrow(EmployeeManager.class)
        .stream()
        .peek(Main::sysout)
        .flatMap(e -> app.getOrThrow(PostManager.class).stream().filter(Post.EMPLOYEE_ID.equal(e.getId())))
        .forEach(Main::sysout);

// トランザクション使う版
app.getOrThrow(TransactionComponent.class).createTransactionHandler().createAndAccept(tx -> {
            app.getOrThrow(EmployeeManager.class)
                    .stream()
                    .peek(Main::sysout)
                    .flatMap(e -> {
                        return app.getOrThrow(PostManager.class)
                                .stream()
                                .filter(Post.EMPLOYEE_ID.equal(e.getId()));
                    })
                    .forEach(Main::sysout);
            tx.rollback();
        });
```
```Main#sysout(Post).java
public static void sysout(Post p) {
    System.out.format("\t%1s: %2s, %3s\n", p.getId(), p.getEmployeeId(), p.getName());
}
```

#要点
- Sreamの操作がResultSetの操作に直結している
    - つまりStreamの終端操作段階で操作の最適化が実行される
    - 現段階ではテーブル結合の際に別Streamから操作する都合上LazyFetchしかできないと思われる
        - ……そもそもこれは結合していない気がする、もっと正しい作法があるのかしら
- JavaMagazineに載るぐらいには注目株
- このStreamを安易にreturnしたり引数にしたりしてはならない、絶対にだ
- Stream操作毎にSQLに関連付けされているイメージなので少し習熟が必要
- パフォーマンスについては上記の件もあるため少々不安が残る、要調査

#ハマったポイント
- トランザクション使おうと思ったらQuick Startではいきなり「txHandler.createAndAccept(tx -> {」とかなってた
    - txHandlerはどこから来たんだよ、となり少し探す羽目に

#後ポスト
まだない。

#参考記事
- [Speedment is a Stream ORM Java Toolkit and Runtime](https://github.com/speedment/speedment)
- [Transactions Made Simple Using Speedment 3.0.17 and Above](https://www.javacodegeeks.com/2017/11/transactions-made-simple-using-speedment-3-0-17.html)
- [Java-MJ17-FluentORM.pdf](http://www.oracle.com/webfolder/technetwork/jp/javamagazine/Java-MJ17-FluentORM.pdf)