C# sqlite 俺用まとめ

System.Data.Sqlite

C#でのSQLite実装のひとつがこれ
標準じゃなくて後からインストールするコンポーネント
sqliteのソースをC#に移植しているため少し遅いらしい

参考にしたページ

System.Data.SQLiteの自作ラッパクラス | jikkenjo.net
ラッパークラスを書いている方がいてとても参考になった
いくつか難点はあったけど要点を読むにはいい材料でした

DBの開け方/閉め方

コネクションはIDisposableなのでusing文にも組み込める

using(SQLiteConnection con = new SQLiteConnection("Data Source=" + dbpath))
{
  con.Open()
  ...
  con.Close()
}

トランザクション発行

発行してコミットまではこんな感じ

using(SQLiteTransaction trans = con.BeginTransaction())
{
...
  trans.Commit();
}

insertなどはトランザクションを発行しないととんでもなく遅くなる

sqlの発行

create文

引数なし戻り値なしは以下のような感じ

string sql = @"create table tagstr(tag text primary key, data text);";
using (SQLiteCommand cmd = con.CreateCommand())
{
  cmd.CommandText = sql;
  cmd.ExecuteNonQuery();
}
insert文

パラメータありで戻り値はなしの場合

// sqlのパラメータ部分には"?"を入れておく
string sql = @"insert into tagstr values (?,?)"
using (SQLiteCommand cmd = con.CreateCommand())
{
    cmd.CommandText = sql;
    //パラメータのセットと確定
    cmd.Parameters.Add(new SQLiteParameter(DbType.String, tag)); 
    cmd.Parameters.Add(new SQLiteParameter(DbType.String, data)); 
    cmd.Prepare();
    
    cmd.ExecuteNonQuery();
}
select文

パラメータと戻り値がある場合

// sqlのパラメータ部分には"?"を入れておく
string sql = @"select data from tagstr where tag=?;";
using (SQLiteCommand cmd = con.CreateCommand())
{
    cmd.CommandText = sql;
    //パラメータのセットと確定
    cmd.Parameters.Add(new SQLiteParameter(DbType.String, tag)); 
    cmd.Prepare();

    //ExecuteReaderするとreaderが帰ってくる
    using (SQLiteDataReader reader = cmd.ExecuteReader())
    {
        //行の読み込み
        while (reader.Read())
        {
            //カラムの取り込み
            string data = (string)reader[0];
            //...
        }
    }
}

自作ラッパー

コマンドパラメータの設定が煩雑なので
その周りだけ簡単にするラッパーを書いたよ

class MySQLiteCon : IDisposable
{
    SQLiteConnection con;
    public MySQLiteCon(string dbpath)
    {
        this.con = new SQLiteConnection("Data Source=" + dbpath);
        if (con == null)
        {
            throw new SQLiteException("DB接続に失敗しました");
        }
        con.Open();
    }

    public MySQLiteCmd Command(string sql)
    {
        SQLiteCommand cmd = con.CreateCommand();
        cmd.CommandText = sql;
        return new MySQLiteCmd(cmd);
    }

    public SQLiteTransaction BeginTransaction()
    {
        return con.BeginTransaction();
    }

    public void Close()
    {
        con.Close();
    }

    public void Dispose()
    {
        con.Close();
        con.Dispose();
    }
}

class MySQLiteCmd : IDisposable
{
    SQLiteCommand cmd;
    List<SQLiteParameter> args;
    
    public MySQLiteCmd(SQLiteCommand baseCmd)
    {
        this.cmd = baseCmd;
        this.args = new List<SQLiteParameter>();
    }

    public MySQLiteCmd(MySQLiteCmd src)
    {
        this.cmd = src.cmd;
        this.args = new List<SQLiteParameter>(src.args);
    }

    private void SetParameters()
    {
        cmd.Parameters.Clear();
        foreach(SQLiteParameter arg in args)
        {
            cmd.Parameters.Add(arg);
        }
        cmd.Prepare();
    }

    public int ExecuteNonQuery()
    {
        SetParameters();
        return cmd.ExecuteNonQuery();
    }

    public SQLiteDataReader ExecuteReader()
    {
        SetParameters();
        return cmd.ExecuteReader();
    }
    public object ExecuteScalar()
    {
        SetParameters();
        return cmd.ExecuteScalar();
    }

    public MySQLiteCmd Arg(DbType type , object arg)
    {
        MySQLiteCmd result = new MySQLiteCmd(this);
        SQLiteParameter param = cmd.CreateParameter();
        param.DbType = type;
        param.Value = arg;
        result.args.Add(param);
        return result;
    }

    public MySQLiteCmd Arg(Int32 arg)
    {
        return Arg(DbType.Int32, arg);
    }

    public MySQLiteCmd Arg(Int64 arg)
    {
        return Arg(DbType.Int64, arg);
    }

    public MySQLiteCmd Arg(string arg)
    {
        return Arg(DbType.String, arg);
    }
    
    //以下Argの定義を好きなだけ増やしてね

    public void Dispose()
    {
        cmd.Dispose();
    }
}

ラッパーの使い方

DBの開きかた
MySQLiteCon con = new MySQLiteCon(dbpath);
create文

パラメータは無いので大体一緒

string sql = @"create table tagstr(tag text primary key, data text);";
using (MySQLiteCmd cmd = con.Command(sql))
{
    cmd.ExecuteNonQuery();
}
select文

パラメータ設定が以下のように簡単になる

string sql = @"select data from tagstr where tag=?;";
using (MySQLiteCmd cmd = con.Command(sql).Arg(tag))
using (SQLiteDataReader reader = cmd.ExecuteReader())
{
    while (reader.Read())
    {
        string data = (string)reader[0];
        ...
    }
}
insert文

コマンドは不変オブジェクトにしてあるため
insertのパラメータを変更して何度も使える

sql = @"insert into exts values (?)";
using (MySQLiteCmd cmd = con.Command(sql))
{
    foreach (string ext in exts)
    {
        cmd.Arg(ext).ExecuteNonQuery();
    }
}

その他

php/pythonsqliteモジュールと同じ気持ちで挑まない方がいいかも

System.Data.Sqlite自体は暗黙で"begin"を発行したりしないため
トランザクションを貼らないとinsertが本気で遅かったり

また標準のライブラリでもないため配布が面倒かも
Accessデータベースやsql server compactとか
標準で組み込みのDBも考えてみるといいかもね

そんなかんじ