くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

AndroidのORM「ormlite」を使う(JOIN編)

AndroidのORMとしてormliteを利用してるが、JOINを使おうとしてハマったので、その備忘録。

現象としては、JOINしたテーブルの情報がIDのみしか取得できず、他のカラムはnullのままになってしまう。。。

解決策としては、JOINしたいフィールドのアノテーションforeignAutoRefresh = trueした。

でも、常にJOINされている感じになるので、性能的に悪そう。。。

Entityクラス

Entityクラスのサンプルはこんな感じ。

@DatabaseTable(tableName = BookEntity.TABLE_NAME)
public class BookEntity {
    public static final String TABLE_NAME = "book";
    public static final String BOOK_ID = "book_id";
    public static final String BOOK_TITLE = "book_title";
    public static final String BOOK_AUTHOR = "book_author";

    @DatabaseField(generatedId = true, columnName = BOOK_ID)
    private Long bookId;
    @DatabaseField(columnName = BOOK_ISBN)
    private String bookTitle;
    @DatabaseField(foreign = true, columnName = BOOK_AUTHOR, foreignAutoRefresh = true)
    private AuthorEntity bookAuthor;
}
@DatabaseTable(tableName = AuthorEntity.TABLE_NAME)
public class AuthorEntity {
    public static final String TABLE_NAME = "author";
    public static final String AUTHOR_ID = "author_id";
    public static final String AUTHOR_NAME = "author_name";

    @DatabaseField(generatedId = true, columnName = BOOK_ID)
    private Long authorId;
    @DatabaseField(columnName = AUTHOR_NAME)
    private String authorName;
}

クエリ

クエリは単純で、以下な感じ。

DBHelper helper = new DBHelper(context);
try {
    Dao<BookEntity, Integer> dao = helper.getDao(BookEntity.class);
    List<BookEntity> result = dao.queryForAll();
} catch (SQLException e) {
    Log.e(TAG, "例外が発生しました", e);
} finally {
    helper.close();
}

なにがうまくいかなかったのか->join()が使えない。。。

はじめは、以下のような感じにしていた。

@DatabaseTable(tableName = BookEntity.TABLE_NAME)
public class BookEntity {
    ・・・
    @DatabaseField(foreign = true, columnName = BOOK_AUTHOR)
    private AuthorEntity bookAuthor;
}

クエリも、公式に書いてる通り、join()メソッドでセットしてquery()を実行。

DBHelper helper = new DBHelper(context);

Dao<BookEntity, Integer> bookDao = helper.getDao(BookEntity.class);
Dao<AuthorEntity, Integer> authorDao = helper.getDao(FollowerEntity.class);

QueryBuilder<BookEntity,Integer> bookQb = bookDao.queryBuilder();
QueryBuilder<AuthorEntity,Integer> authorQb = authorDao.queryBuilder();
PreparedQuery<BookEntity> prepare = bookQb.join(authorQb).prepare();

List<BookEntity> result = bookDao.query(prepare);

なんかできているように見えるが。。。

以下のようなJUnitコードでテストしてみると、通ってしまう。。。 assertNull(entity.getAuthor().getAuthorName);ってなんだよ、おい

for(BookEntity entity : result) {
    assertNotNull(entity);
    assertNotNull(entity.getAuthor());
    assertNotNull(entity.getAuthor().getAuthorId);
    assertNull(entity.getAuthor().getAuthorName);
}

はじめのうちは、AutherがNullではないので、いいかなーと思っていたらそうではないし、 わけわからんと思って、ormliteが生成するSQLを見てみるとこんな感じだった。。。

・・・
PreparedQuery<BookEntity> prepare = bookQb.join(authorQb).prepare();
Log.e(this.getClass().getSimpleName(), prepare.getStatement());
SELECT `book`.* FROM `tweet` INNER JOIN `author` ON `book`.`book_author` = `author`.`_id`

おぉ?取ってくるカラムが、bootテーブルだけに限定されている。。。そりゃauthorテーブルの情報は取ってこないわ。。。

RawRowMapperを使うとうまく扱えそう?

以下の記事を見ていると、生SQLの結果をマッピングする機能があるらしい。 - ORMLite使い方メモ - Qiita

いっそのこと生のSQLを書いて、これをそのままor拡張して使えばいい感じ扱えるかもしれないが、ORMを使っているのに生SQLを書くってのも。。。ってことで、最初に書いた解決策を選択。

日本語の情報が少ないので、なんともかんとも。。。

とりあえず以上!

参考にしたサイト様