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を書くってのも。。。ってことで、最初に書いた解決策を選択。
日本語の情報が少ないので、なんともかんとも。。。
とりあえず以上!