Android開発でデータベース接続を使ってみた

#はじめに
こんにちは。某学校でプログラミング等の勉強中のサーバーサイドのプログラマーのワタタクです。:relaxed:
今回はWEBプログラミングではなく、Androidを開発していきたいと思います。
#対象者
- Javaがそこそこ書ける人。
- Android開発においてもそこそこできる人。

#利用手順
①DBのヘルパークラスを用意する。
②アクティビティでヘルパークラスからDB接続オブジェクト(**SQLiteDatabaseオブジェクト**)をもらう。
③DB接続オブジェクトを使ってSQLを実行していく。
#DBのヘルパークラスの作り方
**SQLiteOpenHelperクラス**を**継承**して作る。
この際三つのメソッドを実装する。
⒈コンストラクタ
⒉onCreate()
⒊onUpgrade()

##⒈コンストラクタ
コンストラクタを作成してその中で、*supper(4つの引数)*を記述する。
###＜引数１＞
*コンテキスト*
＊コンテキストはこのクラスでは用意できないため、このクラスを使うアクティビティから引数としてもらう。
###＜引数２＞
*使用するデータベースファイル名*
###＜引数３＞
*カーソルファクトリーオブジェクト*
＊通常はnullでよい
###＜引数４＞
*DBのヴァージョン番号*
＊整数で１始まり。
＊Androidは内部DBがヴァージョン番号と一緒に管理されているので、渡す番号より内部の番号が小さい時に**onUpgrade()**が実行される。
##⒉onCreate()
＊内部にデータベースが存在しないときに一回だけ実行されるメソッド。
＊CREATE TABLEなどの初期設定に必要なSQLをここに書く。
＊引数のdbでの**execSQL()**を使ってSQL文実行。
##⒊onUpgrade()
以下の第二、第三引数の違いを利用してALTER TABLEなどのDB内部構造を変更する。
第一：DB接続オブジェクト。
第二：現在の内部番号。
第三：コンストラクタで設定した番号。
#DBヘルパークラスの例

```java:DatabaseHelper.java
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DatabaseHelper extends SQLiteOpenHelper {
    private static final String DATABASE_NAME = "データベース名";
    private static final int DATABASE_VERSION = 1;

    public DatabaseHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db ) {
        StringBuffer sb = new StringBuffer();
        sb.append("CREATE TABLE テーブル名 (");
        sb.append("_id INTEGER PRIMARY KEY AUTOINCREMENT, ");
        sb.append("content TEXT, ");
        sb.append(");");
        String sql = sb.toString();

        db.execSQL(sql);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}
```
#データアクセス
##基本手順
①ヘルパーオブジェクト生成
②ヘルパーからDB接続オブジェクトをもらう。
③データ処理
④DB接続オブジェクトの解放

```java:〜〜〜〜Activity.java
①　DatabaseHelper helper = new DatabaseHelper(コンテキスト);
②　SQLiteDatabase db = helper.getWritableDatabase();
try {

③    //DB処理

} catch(Exception ex) {

    Log.e("MemoPad", ex.toString());

} finally {

④    db.close();

}
```
##更新系(INSERT,UPDATE,DELETE)
①SQL文字列を生成

②ステートメントオブジェクトをもらう

```
SQLiteStatement stmt = db.compileStatement("SQL文字列");
```

③変数のバインド

```
stmt.bindデータ型(？の順番, 値);
```

④SQLを実行する

- INSERT

```
stmt.executeInsert();
```
- UPDATE,DELETE

```
stmt.executeUpdateDelete();
```
##参照系(SELECT)
①SQL文字列を生成

②SQLを実行する

```
 Cursor cursor = db.rawQuery("SQL文字列", null);
```

③Cursorをループする

```
while (cursor.moveToFirst()) {}
```
＊あきらかに結果が１行の時は``if (cursor.moveToFirst()) {}``

④各行のデータを取得する

```
int 変数 = cursor.getColumnIndex("カラム");
           
String カラム = cursor.getカラムのデータ型(変数);
```
#データアクセスの例
＊Memoテーブルがあるとしてそれを操作するとする

```java:DataAccess.java

import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteStatement;

import java.sql.Timestamp;

public class DataAccess {
    public static Memo findByPK(SQLiteDatabase db, int id) {
        String sql = "SELECT _id, title, content, update_at FROM memos WHERE _id = " + id;
        Cursor cursor = db.rawQuery(sql, null);
        Memo result = null;
        if (cursor.moveToFirst()) {
            int idxTitle = cursor.getColumnIndex("title");
            int idxContent = cursor.getColumnIndex("content");
            int idxUpdateAt = cursor.getColumnIndex("update_at");
            String title = cursor.getString(idxTitle);
            String content = cursor.getString(idxContent);
            String updateAtStr = cursor.getString(idxUpdateAt);

            Timestamp updateAt = Timestamp.valueOf(updateAtStr);

             /*
             *セッター
             */
            result = new Memo();
            result.setId(id);
            result.setTitle(title);
            result.setContent(content);
            result.setUpdateAt(updateAt);

        }
        return result;
    }

    public static int update(SQLiteDatabase db, int id, String title, String content) {
        String sql = "UPDATE memos SET title = ?, content = ?, update_at = datetime('now') WHERE _id = ?";
        SQLiteStatement stmt = db.compileStatement(sql);
        stmt.bindString(1, title);
        stmt.bindString(2, content);
        stmt.bindLong(3, id);
        int result = stmt.executeUpdateDelete();
        return result;
    }

    public static long insert(SQLiteDatabase db, String title, String content) {
        String sql = "INSERT INTO memos (title, content, update_at) VALUES (?, ?, datetime('now'))";
        SQLiteStatement stmt = db.compileStatement(sql);
        stmt.bindString(1, title);
        stmt.bindString(2, content);
        long id = stmt.executeInsert();
        return id;
    }

    public static int delete(SQLiteDatabase db, int id) {
        String sql = "DELETE FROM memos WHERE _id = ?";
        SQLiteStatement stmt = db.compileStatement(sql);
        stmt.bindLong(1, id);
        int result = stmt.executeUpdateDelete();
        return result;
    }
}
```

```
MVCを採用してDB処理をモデルとして別クラスに記述するとき③データ処理をメソッド化する。
その際それらのメソッドを 「static」 にすることでDAOクラスをnewしなくて良いからメモリの節約になる。
```

以上。
もし何か間違っている等のご指摘があればご連絡ください。
最後まで読んで頂きありがとうございました。