40
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ORMLite使い方メモ

Last updated at Posted at 2014-08-15

Android で利用した場合の使い方をメモする。

#ORMLite とは
Android でも使える O/R マッパー。

メソッド名を見ればなんとなく使い方が分かるので、使いやすそうな印象。

#Hello World
##インストール

build.gradle
dependencies {
    compile 'com.j256.ormlite:ormlite-android:4.48'
}

##実装

TestTable.java
package com.example.ormlitesample;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable
public class TestTable {
    
    @DatabaseField(id=true)
    private Long id;
    @DatabaseField
    private String code;
    @DatabaseField
    private String value;
    
    @SuppressWarnings("unused")
    private TestTable() {}
    
    public TestTable(Long id, String code, String value) {
        this.id = id;
        this.code = code;
        this.value = value;
    }

    @Override
    public String toString() {
        return "TestTable [id=" + id + ", code=" + code + ", value=" + value + "]";
    }
}
MyDatabaseHelper.java
package com.example.ormlitesample;

import java.sql.SQLException;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;

import com.j256.ormlite.android.apptools.OrmLiteSqliteOpenHelper;
import com.j256.ormlite.support.ConnectionSource;
import com.j256.ormlite.table.TableUtils;

public class MyDatabaseHelper extends OrmLiteSqliteOpenHelper {
    
    private static final String DATABASE_NAME = "ormlite.sample";
    private static final int DATABASE_VERSION = 1;
    
    public MyDatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db, ConnectionSource connectionSource) {
        System.out.println("MyDatabaseHelper.onCreate()");
        try {
            TableUtils.createTable(connectionSource, TestTable.class);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, ConnectionSource connectionSource, int oldVersion, int newVersion) {
        System.out.println("MyDatabaseHelper.onUpgrade()");
    }
}
MainActivity.java
package com.example.ormlitesample;

import java.sql.SQLException;

import android.os.Bundle;

import com.j256.ormlite.android.apptools.OrmLiteBaseActivity;
import com.j256.ormlite.dao.Dao;

public class MainActivity extends OrmLiteBaseActivity<MyDatabaseHelper> {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        try {
            Dao<TestTable, Long> dao = getHelper().getDao(TestTable.class);
            
            TestTable hoge = new TestTable(1L, "a", "A");
            dao.create(hoge);
            
            TestTable table = dao.queryForId(1L);
            
            System.out.println(table);
            
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

##動作結果

I/System.out(1935): MyDatabaseHelper.onCreate()
I/System.out(1935): TestTable [id=1, code=hoge, value=HOGE]

##説明

  • データベースとマッピングするクラス(TestTable)は、 @DatabaseTable でアノテートする。
    • カラムとマッピングさせるフィールドは、 @DatabaseField でアノテートする。
    • フィールドの Getter/Setter は不要(private でも構わない)。
    • 引数なしのコンストラクタが必須(private でも構わない)。
  • データベースアクセスには、 OrmLiteSqliteOpenHelper を継承したクラスを作成する。
    • TableUtils.createTable() を使うと、クラスに設定したアノテーションの情報をもとにテーブルを自動生成してくれる。
  • アクティビティは OrmLiteBaseActivity を継承して作成する。
    • 型引数に、作成した OrmLiteSqliteOpenHelper のサブクラスを渡す。
    • getHelper().getDao(Class) で、デーブルごとの Dao を取得する。

###Dao 生成はコストが高い
Dao の生成はコストが高いらしく、1度生成したらできる限り使い回したほうが良いらしい。

Building a DAO can be an expensive operation and for devices with limited resources (like mobile apps), DAOs should be reused if at all possible.

2.4 Setting Up the DAOs | ORMLite Documentation: 2. How to Use

#OrmLiteBaseActivity を継承しない方法

MainActivity.java
package com.example.ormlitesample;

import java.sql.SQLException;

import android.app.Activity;
import android.os.Bundle;

import com.j256.ormlite.android.apptools.OpenHelperManager;
import com.j256.ormlite.dao.Dao;

public class MainActivity extends Activity {
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        try {
            MyDatabaseHelper helper = OpenHelperManager.getHelper(this, MyDatabaseHelper.class);
            
            Dao<TestTable, Long> dao = helper.getDao(TestTable.class);
            
            TestTable hoge = new TestTable(1L, "hoge", "HOGE");
            dao.create(hoge);
            
            TestTable table = dao.queryForId(1L);
            
            System.out.println(table);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        OpenHelperManager.releaseHelper();
    }
}
  • OpenHelperManager.getHelper() メソッドで、ヘルパークラスを取得できる。
  • この場合、アクティビティが削除されるときに OpenHelperManager.releaseHelper() を呼ばなければならない。

#SQLException をスローしない Dao を取得する

package com.example.ormlitesample;

import android.os.Bundle;

import com.j256.ormlite.android.apptools.OrmLiteBaseActivity;
import com.j256.ormlite.dao.RuntimeExceptionDao;

public class MainActivity extends OrmLiteBaseActivity<MyDatabaseHelper> {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        RuntimeExceptionDao<TestTable, Long> dao = getHelper().getRuntimeExceptionDao(TestTable.class);
        
        TestTable table = dao.queryForId(1L);
        
        System.out.println(table);
    }
}
  • getRuntimeExceptionDao(Class) で、 SQLException をスローしない Dao を取得できる。

#アノテーションで設定する
##@DatabaseTable
###tableName

  • テーブル名を指定する。
  • 省略した場合は、クラス名を小文字にしたものが使用される。

##@DatabaseField

全部書いてると大変なので、主要そうなのだけ。

その他の属性は ORMLite Documentation: 2. How to Use を参照。

###columnName

  • カラム名を指定する。

###dataType

###defaultValue

  • レコードを登録するときの初期値を設定する。

###width

  • カラムのサイズを指定する。
  • 主に文字列型のカラムのサイズを指定するのに使用する。
  • 0 の場合はデータベースのデフォルトのサイズが使用される。

###canBeNull

  • NULL 可項目にするかどうかを boolean で指定する。
  • デフォルトは true。

###id

  • プライマリキーであることを指定する。
  • クラス内で、1つのフィールドにのみ設定できる。
  • Dao の **ForId() などのメソッドは、id = true の項目が使用される。

###generatedId

  • プライマリキーの値がデータベースによって自動生成されることを指定する。
  • クラス内で、1つのフィールドにのみ設定できる。
  • id 属性とは排他的に指定する。

###foreign

  • true を指定すると、そのフィールドが他のテーブルの ID を参照していることを指定できる。
  • Java クラス上は、参照するテーブルクラスをフィールドとして持つようにする。
ForeignTable.java
package com.example.ormlitesample;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable
public class ForeignTable {

    @DatabaseField(generatedId=true)
    private Long id;
    @DatabaseField
    private String value;
    
}
TestTable.java
package com.example.ormlitesample;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

@DatabaseTable
public class TestTable {
    
    @DatabaseField(generatedId=true)
    private Long id;
    @DatabaseField(foreign=true)
    private ForeignTable foreign;
}

###useGetSet

  • true を設定すると、値の取得は Getter/Setter を通じて行われるようになる。
  • デフォルトは、リフレクションを使ってフィールドを直接参照する。

###unknownEnumName

  • DB から読み込んだレコードに enum の列挙子に存在しない値が存在した場合、どの列挙子にマッピングするかを文字列で指定する。
  • デフォルトは、存在しない列挙子を読み込んだ場合、 SQLException がスローされる。

###persisted

  • false を設定すると、そのフィールドはデータベースに保存されなくなる。

###unique

  • true を設定すると、その項目にユニークキー制約が設定される。
  • 複数項目でユニークキーを設定する場合は、 uniqueCombo を使う。

###uniqueCombo

  • true を設定した複数の項目でユニークキー制約を設定する。

###uniqueIndexName

  • 名前を指定してユニークキー制約を設定する。
  • 同じ名前を設定したフィールドで1つのユニークキー制約を設定できる。

#QueryBuilder を使って検索する
##基本

package com.example.ormlitesample;

import java.sql.SQLException;
import java.util.List;

import android.os.Bundle;

import com.j256.ormlite.android.apptools.OrmLiteBaseActivity;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;

public class MainActivity extends OrmLiteBaseActivity<MyDatabaseHelper> {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        try {
            Dao<TestTable, Long> dao = getHelper().getDao(TestTable.class);
            
            QueryBuilder<TestTable, Long> queryBuilder = dao.queryBuilder();
            
            PreparedQuery<TestTable> preparedQuery = queryBuilder.where().eq("value", "hoge").prepare();
            
            List<TestTable> list = dao.query(preparedQuery);
            
            System.out.println(list);
            
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
  • Dao.queryBuilder() でビルダーを取得する。
  • ビルダーで検索条件を設定し、最後に prepare() メソッドで PreparedQuery のインスタンスを取得する。
  • 取得した PreparedQueryDao.query() に渡す。

##AND, OR 条件を使う
###普通に連結する

QueryBuilder<TestTable, Long> builder = dao.queryBuilder();

builder.where().eq("value", "hoge")
               .or()
               .eq("value", "fuga");
WHERE value = 'hoge'
   OR value = 'fuga' 
  • and() または or() メソッドで AND, OR を指定できる。

###グループ化する

QueryBuilder<TestTable, Long> builder = dao.queryBuilder();

Where<TestTable, Long> where = builder.where();

where.or(
    where.and(
        where.eq("code", "hoge"),
        where.eq("value", "HOGE")
    ),
    where.and(
        where.eq("code", "piyo"),
        where.eq("value", "PIYO")
    )
);

PreparedQuery<TestTable> query = builder.prepare();
WHERE (code = 'hoge' AND value = 'HOGE')
   OR (code = 'piyo' AND valud = 'PIYO')
  • Where オブジェクトを使って、複雑な条件式を作ることができる(難読化しそうで恐い)。

その他にも distinct() とか orderBy() とか、様々なメソッドがビルダーに用意されている。
3.4 QueryBuilder Capabilities | ORMLite Documentation: 3. Custom Statement Builder この辺を見れば、だいたい使い方は分かる気がする。

#生 SQL を実行する

MainActivity.java
package com.example.ormlitesample;

import java.sql.SQLException;

import android.os.Bundle;

import com.j256.ormlite.android.apptools.OrmLiteBaseActivity;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.GenericRawResults;
import com.j256.ormlite.field.DataType;

public class MainActivity extends OrmLiteBaseActivity<MyDatabaseHelper> {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        try {
            Dao<TestTable, Long> dao = getHelper().getDao(TestTable.class);
            
            String sql = "SELECT * FROM testtable WHERE value = ?";
            DataType[] dataTypes = {DataType.LONG_OBJ, DataType.STRING};
            
            GenericRawResults<Object[]> result = dao.queryRaw(sql, dataTypes, "HOGE");
            
            for (Object[] row : result) {
                for (Object column : row) {
                    System.out.println("class=" + column.getClass() + ", value=" + column);
                }
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
LogCat出力
I/System.out(12073): class=class java.lang.Long, value=1
I/System.out(12073): class=class java.lang.String, value=HOGE
  • Dao.queryRow() という名前のメソッドがいくつかオーバーロードされており、これらは生の SQL を実行できる。
  • COUNT を取りたいときとかは、 queryRawValue() という long 値を返すメソッドが用意されている。

##生 SQL を書いたけど、結局 Java クラスにマッピングできるように SELECT している場合
複雑な JOIN とかしたけど、結局 SELECT しているのは1つのテーブルの項目だけで、そのままクラスにマッピングして欲しいときとかは、以下のようにするといいと思う。

package com.example.ormlitesample;

import java.sql.SQLException;

import android.os.Bundle;

import com.j256.ormlite.android.apptools.OrmLiteBaseActivity;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.GenericRawResults;
import com.j256.ormlite.dao.RawRowMapper;

public class MainActivity extends OrmLiteBaseActivity<MyDatabaseHelper> {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        try {
            Dao<TestTable, Long> dao = getHelper().getDao(TestTable.class);
            
            String sql = "SELECT * FROM testtable";
            RawRowMapper<TestTable> mapper = dao.getRawRowMapper();
            
            GenericRawResults<TestTable> result = dao.queryRaw(sql, mapper);
            
            for (TestTable row : result) {
                System.out.println(row);
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}
  • queryRow() の第二引数に、 dao から取得しておいた TestTable クラス用の RawRowMapper を渡す。

#RoboGuice と連携する

MyDatabaseHelperProvider.java
package com.example.ormlitesample;

import javax.inject.Inject;

import roboguice.activity.event.OnCreateEvent;
import roboguice.activity.event.OnDestroyEvent;
import roboguice.event.Observes;
import roboguice.inject.ContextSingleton;
import android.app.Activity;

import com.j256.ormlite.android.apptools.OpenHelperManager;
import com.j256.ormlite.dao.RuntimeExceptionDao;

@ContextSingleton
public class MyDatabaseHelperProvider {

    @Inject
    private Activity activity;
    
    private MyDatabaseHelper helper;
    private RuntimeExceptionDao<TestTable, Long> testTableDao;
    
    public void onActivityCreate(@Observes OnCreateEvent event) {
        this.helper = OpenHelperManager.getHelper(this.activity, MyDatabaseHelper.class);
    }
    
    public void onActivityDestroy(@Observes OnDestroyEvent event) {
        OpenHelperManager.releaseHelper();
    }
    
    public RuntimeExceptionDao<TestTable, Long> getTestTableDao() {
        if (this.testTableDao == null) {
            this.testTableDao = this.helper.getRuntimeExceptionDao(TestTable.class);
        }
        
        return this.testTableDao;
    }
}
MainActivity.java
package com.example.ormlitesample;

import java.util.List;

import javax.inject.Inject;

import roboguice.activity.RoboActivity;
import roboguice.inject.ContentView;
import android.os.Bundle;

import com.j256.ormlite.dao.RuntimeExceptionDao;

@ContentView(R.layout.activity_main)
public class MainActivity extends RoboActivity {
    
    @Inject
    private MyDatabaseHelperProvider provider;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        RuntimeExceptionDao<TestTable, Long> dao = this.provider.getTestTableDao();
        
        List<TestTable> list = dao.queryForAll();
        
        for (TestTable t : list) {
            System.out.println(t);
        }
    }
}
  • MyDatabaseHelper を供給するクラスを @ContextSingleton スコープで定義する。
  • @Observes を使うことで、 onDestory() 時のリリース漏れが無いようにしている(これで使い回しがしやすくなる気がする)。

#参考

40
40
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
40
40

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?