How to manage SQLite's database file names
SQLite の名前空間に関する問題
Android で SQLite を扱う場合、SQLiteOpenHelper を利用するのが一般的だと思いますが、その際にデータベースファイル名を指定する必要があります。*1*2
データベースファイル名は同一アプリケーション内部で共有されるため、アドホックに管理すると、意図しない名前衝突が起こる可能性があります。*3
今回は、この名前衝突を回避する方法を模索してみようと思います。
名前衝突を回避する方法の模索
データベースをアプリケーションで1つにする方法
1アプリ1データベースという方式にすれば、アプリ内部でのDB名の衝突は起こりません。この方法は、データ構造が単純かつ、データの管理をひとりで行うような場合はアリかもしれません。しかし、時間の経過とともにデータ構造が複雑化されていくことも十分に考えられるため、分割統治する仕組みがあったほうが無難かもしれません。
データベースファイル名を集中管理し、データベース自体は個別管理する方法
データベースファイル名を集中管理し、データベース自体は個別管理する方法では、データベースファイル名の一元管理と、複数のデータベースの相互非依存な個別管理が可能になります。
どちらの方法を採用するか?
特にDBを分ける明確な理由がない間は単一DBで運用し、必要が生じたときにDBを分割するという方法がよさそうです。DBを分割してしまうと、追加の複雑さを導入してしまうというデメリットもありますが、それ以上に、異なるDB間でテーブルのjoinができなくなるという点が致命的。開発初期は相互に無関係のデータだと思っていても、後になってjoinする必要性が出てくるということはありうるし、それは未来予知能力がない限りわからんですよね。
実現方法
enum によるデータベース名の集中管理
データベース名の集中管理を行うための enum を作成します。enum として扱うことにより、実装の分散を防ぎます。
public enum SQLiteDatabaseIdentifier { TEST_DATABASE(1); private final int version; SQLiteDatabaseIdentifier(int version) { this.version = version; } public int version() { return version; } }
SQLiteDatabaseIdentifier を扱う SQLiteOpenHelper の作成
SQLiteDatabaseIdentifier を扱うことを強制された SQLiteOpenHelper を作成します。これを利用することで、データベースファイル名の一元管理と複数のデータベースの相互非依存な個別管理が可能になります。
import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import static android.database.sqlite.SQLiteDatabase.CursorFactory; public abstract class SQLiteDatabaseIdentifierAwareSQLiteOpenHelper extends SQLiteOpenHelper { public SQLiteDatabaseIdentifierAwareSQLiteOpenHelper(Context context, SQLiteDatabaseIdentifier id, CursorFactory factory) { super(context, id.name(), factory, id.version()); } }
SQLiteDatabaseIdentifierAwareSQLiteOpenHelper の実装例
package com.objectfanatics.example; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; public class DbHelper extends SQLiteDatabaseIdentifierAwareSQLiteOpenHelper { private static final SQLiteDatabaseIdentifier sqLiteDatabaseIdentifier = SQLiteDatabaseIdentifier.TEST_DATABASE; public DbHelper(Context context) { super(context, sqLiteDatabaseIdentifier, null); } @Override public void onCreate(SQLiteDatabase sqLiteDatabase) { String sql1 = "create table User (name text primary key)"; sqLiteDatabase.execSQL(sql1); String sql2 = "insert into User (name) values ('John Smith')"; sqLiteDatabase.execSQL(sql2); } @Override public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i2) { } public String getName() { Cursor c = getReadableDatabase().rawQuery("select name from User", null); c.moveToFirst(); return c.getString(c.getColumnIndex("name")); } }
まとめ
今回は、データベース名(とバージョン)の一元管理を行いつつ、各データベースの実装を相互非依存にするための簡単な方法をまとめました。
今回は思い付きベースでまとめてみただけなので、もっといいアイデアがあればぜひ教えてください(^^;