Contents
まず、System.Data.SQLiteを使ってました。
NuGetなんて概念が生まれる前に古いSystem.Data.SQLite.dllをダウンロードして使い続けていたので、暗号化がサポートされていたんですよねー
これがNuGetで新しくしたらSetPasswordが使えないでやんの。
なんとか解決してきたので、情報をまとめておきます。
Microsoft.Data.SQLiteを入れるぞよ
最低限の環境用意
NuGetでMicrosoft.Data.SQLiteをインストールする。
依存関係が一式インストールされます。
SqliteConnection connection = new SqliteConnection();
string path = @"なんか良さげな場所\test.db";
bool isCreate = !File.Exists(path);
// Open
connection.ConnectionString = new SqliteConnectionStringBuilder("Data Source=" + path)
{
Mode = SqliteOpenMode.ReadWriteCreate
}.ToString();
connection.Open();
// テーブル作ってみる
if (isCreate)
{
SqliteCommand createTable = connection.CreateCommand();
createTable.CommandText = "良さげなCREATE TABLE文;";
createTable.ExecuteNonQuery();
SqliteCommand insert = connection.CreateCommand();
insert.CommandText = "良さげなINSERT INTO文;";
insert.ExecuteNonQuery();
}
// 更新してみる
// System.Data.SQLliteなら COL_NAME = ?だったけど、それだとダメっぽい。ちゃんと名前をつけてあげて。
SqliteCommand update = connection.CreateCommand();
update.CommandText = "良さげなUPDATE文 SET COL_NAME = $arg1;";
update.Parameters.AddWithValue("$arg1", "hogehoge" + DateTime.Now.ToString());
update.ExecuteNonQuery();
// 読んでみる
SqliteCommand select = connection.CreateCommand();
select.CommandText = "SELECT * FROM 作ったテーブル名;";
using (var reader = select.ExecuteReader())
{
while (reader.Read())
{
for (int i = 0; i < reader.FieldCount; i++)
{
Console.WriteLine("read filed[" + i.ToString() + "] = " + (reader.IsDBNull(i) ? "null" : reader.GetString(i)));
}
}
}
既存のSystem.Data.SQLite使用コードがある場合は、Microsoft.Data.SQLiteに差し替えてください。
見ての通り、クラス名の大文字小文字が地味に違うので、置換が必要です。
暗号化は続けたいんやが?
一度、Microsoft.Data.SQLiteのみをアンインストールします。
続けて、Microsoft.Data.Sqlite.Coreと、SQLitePCLRaw.bundle_e_sqlcipherをインストールします。
今回はSQLitePCLRaw.lib.e_sqlcipher.2.1.4がインストールされたと仮定して話を進めます。
このままだと暗号化に切り替わっていません。
packages\SQLitePCLRaw.lib.e_sqlcipher.2.1.4\runtimeフォルダから、実行環境に応じたフォルダを選択して、中にあるe_sqlcipher.dllを実行フォルダにコピーします。
面倒だったら、実行ファイルのプロジェクトのビルド後イベントに、runtimeフォルダ含めて一式コピーしても良いです。
xcopy /s /r /c /y $(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlcipher.2.1.4 $(TargetDir)
まぁ、乱暴なので、ちゃんと必要なものだけコピーしましょう。
Windowsシリーズ64bitで動かすつもりならこう。
xcopy /y $(SolutionDir)\packages\SQLitePCLRaw.lib.e_sqlcipher.2.1.4\runtimes\win-x64\native\e_sqlcipher.dll $(TargetDir)
さて、これでパスつきで動くはずです。
ただ、今まで使ってたDBとは暗号方式が違うのか、PupSQLite.exeを使っても開けなくなります。
VBA + vbRichClientも使ってアクセスしてたけど、これも使えなくなるのかー
まぁ、私は使う度にDBを作成する系システムを作っているので、無問題としましょう。
困る人はコンバーターでも作ってください。
// この1文も忘れずに
SQLitePCL.Batteries.Init();
// 前述のコードでOpen前にパスワードを指定する
SqliteConnection connection = new SqliteConnection();
string path = @"なんか良さげな場所\test.db";
bool isCreate = !File.Exists(path);
// Open
connection.ConnectionString = new SqliteConnectionStringBuilder("Data Source=" + path)
{
Mode = SqliteOpenMode.ReadWriteCreate,
Password = "つけたいパスワード"
}.ToString();
connection.Open();
// 以下同文なので省略
COM登録したDLLとして動きたいんやが?
さて、exeファイルで動作確認もした。
できたなーと思ってインストーラーで配布したところ、dll単体では動きません。
app.Configに書いてあるassemblyBindingタグの効果が得られないため、SqliteConnectionインスタンス生成時にエラーになります。
実装するクラスのコンストラクタで、リダイレクトするための仕組みをいれておきます。
説明をわけました。
DataAdapterを使いたいんやが?
System.Data.SQLiteを手放さなければ使えるっぽい。
ちなみに、INTERGER型のカラムをintでキャストすると吹っ飛ぶので、longでキャストするか、一度ToString()で文字列にしてint.Parse()でパースしてください。
他の方法を紹介している方もいらっしゃいました。
が、それはINTEGER型のカラム名がわかってないといけなさそう。
共通化に向いてないので、試していません。
// OpenやDB用意は前述の通りなので省略
// DataSetで読んで見る
System.Data.Common.DbCommand select2 = connection.CreateCommand();
select2.CommandText = "SELECT * FROM テーブル名;";
select2.CommandType = System.Data.CommandType.Text;
select2.Connection = connection;
System.Data.Common.DbProviderFactory factory = System.Data.Common.DbProviderFactories.GetFactory("System.Data.SQLite");
System.Data.Common.DbDataAdapter adapter = factory.CreateDataAdapter();
adapter.SelectCommand = select2;
System.Data.DataSet dataset = new System.Data.DataSet();
adapter.Fill(dataset);
foreach (System.Data.DataTable table in dataset.Tables)
{
foreach (System.Data.DataRow row in table.Rows)
{
object[] col = row.ItemArray;
for (int i = 0; i < col.Length; i++)
{
Console.WriteLine("read filed[" + i.ToString() + "] = " + (col[i] == null ? "null" : col[i].ToString()));
}
}
}
DbProviderFactories.GetFactory()でエラーになる場合は、app.configに下記を追加してください。
<system.data>
<DbProviderFactories>
<remove invariant="System.Data.SQLite.EF6" />
<add name="SQLite Data Provider (Entity Framework 6)" invariant="System.Data.SQLite.EF6" description=".NET Framework Data Provider for SQLite (Entity Framework 6)" type="System.Data.SQLite.EF6.SQLiteProviderFactory, System.Data.SQLite.EF6" />
<remove invariant="System.Data.SQLite" />
<add name="SQLite Data Provider" invariant="System.Data.SQLite" description=".NET Framework Data Provider for SQLite" type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite" />
</DbProviderFactories>
</system.data>
COM登録したDLLとして動きたいんやが?
だからapp.configは使いたくないんだってば!
System.Data.SQLiteで空&パスワードなしのDBを作って、それを経由してAdapterを作ってみます。
/* これはapp.configを使う必要が出ちゃうので却下
System.Data.Common.DbProviderFactory factory = System.Data.Common.DbProviderFactories.GetFactory("System.Data.SQLite");
System.Data.Common.DbDataAdapter adapter = factory.CreateDataAdapter();
*/
/* System.Data.SQでパスなしの空DBを作ってAdapterを生成する */
string pathForAdapter = @"良さげな場所\testForAdapter.db";
SQLiteConnection con = new SQLiteConnection("Data Source=" + pathForAdapter);
con.Open();
System.Data.Common.DbDataAdapter adapter = new SQLiteDataAdapter(select2.CommandText, con);
動いたわ…いいの? これで大丈夫なの??
さっくり検証しかしていないので、責任は持ちません。
他にもニッチなIT関連要素をまとめていますので、よければ一覧記事もご覧ください。