コンソールアプリにCRUD機能を実装
CSVファイルへの接続確認ができたところで、アプリにCRUD(Create、Read、Update、Delete)機能を実装していきましょう。ここでは、DataAdapter(C1CSVDataAdapter)を使った例を紹介します。DataReader(C1CSVDataReader)を使った例は配布サンプルを参照してください。
また、ここでは全データ出力のIndex関数と、新規データ登録のCreate関数、データ削除のDelete関数を紹介します。個別行出力のRead関数、データ更新のUpdate関数については、こちらも配布サンプルを参照してください。
作成するアプリの説明
CRUDの操作は、コマンドラインで指示します。アプリのコマンドライン書式は以下の通りとします。
program [ [C|R|U|D] パラメータ]
1番目のパラメータで、CRUDの区別を指定します。省略時はインデックス(全データ)出力とします。パラメータには、CRUDごとに必要なデータを記述します。
- C:新規データをCSV形式で(No列は自動決定されるので省略可)
- R:対象のNo
- U:更新データをCSV形式で(No列に一致する行が置き換えられる)
- D:対象のNo
全データ出力を実装してみる(Index)
ここから、C1CSVDataAdapterを使ってクエリを実装していきます。C1CSVDataAdapterはC1.AdoNet.CSV名前空間にあるので、パッケージの追加は不要です。まずは、一覧表示のためのindex関数です。なお、以降で紹介する関数はコマンドラインパラメータによって振り分けて呼び出されますが、仕分け部分のコードは本記事の主旨とは関係が薄いので、掲載を割愛します。内容は配布サンプルを参照してください。
void index(C1CSVConnection conn) { var adapter = new C1CSVDataAdapter(); (1) adapter.SelectCommand = new C1CSVCommand(conn); (2) adapter.SelectCommand.CommandText = "SELECT * FROM customer"; var dataTable = new DataTable(); (3) adapter.Fill(dataTable); ShowDataTable(dataTable); (4) }
これは、DataAdapterを使う場合の典型的なコードとなっています。CRUDそれぞれの関数でもほぼ同様の展開となります。(1)は、DataAdapterであるC1CSVDataAdapterのインスタンスを生成しています。(2)からは、DataAdapterのSelectCommandプロパティで選択コマンドを生成、設定しています。この場合は全行選択のSQL文となっています。(3)からは、DataTableを生成してFillメソッドでクエリ結果を読み込んでいます。これをもとに、(4)でスキーマ情報と同様に全行を出力しています。プログラムをビルド、引数なしで実行してみて、図3のように全データが出力されることを確認してください。
新規データ登録(Create)を実装してみる
続いて、新規データ登録のCreate関数を紹介します。
void Create(C1CSVConnection conn, string record) { int no = 1; (1) var cmd = conn.CreateCommand(); cmd.CommandText = "SELECT Max([No]) FROM customer"; var obj = cmd.ExecuteScalar(); if (obj != null) { no = Convert.ToInt32(obj); no++; } string[] fields = record.Split(','); (2) var adapter = new C1CSVDataAdapter(conn, "SELECT * FROM customer"); (3) var dataTable = new DataTable(); adapter.Fill(dataTable); adapter.InsertCommand = new C1CSVCommand(conn); (4) adapter.InsertCommand.CommandText = "INSERT INTO customer([No],[氏名],[氏名(ひらがな)],[メールアドレス],[電話番号],[郵便番号],[住所],[会社名]) VALUES(@No,@Name,@Kana,@Email,@Tel,@Zip,@Address,@Company)"; adapter.InsertCommand.Parameters.Add("@No", "No"); adapter.InsertCommand.Parameters.Add("@Name", "氏名"); adapter.InsertCommand.Parameters.Add("@Kana", "氏名(ひらがな)"); adapter.InsertCommand.Parameters.Add("@Email", "メールアドレス"); adapter.InsertCommand.Parameters.Add("@Tel", "電話番号"); adapter.InsertCommand.Parameters.Add("@Zip", "郵便番号"); adapter.InsertCommand.Parameters.Add("@Address", "住所"); adapter.InsertCommand.Parameters.Add("@Company", "会社名"); var customerRow = dataTable.NewRow(); (5) customerRow["No"] = no; customerRow["氏名"] = fields[1]; customerRow["氏名(ひらがな)"] = fields[2]; customerRow["メールアドレス"] = fields[3]; customerRow["電話番号"] = fields[4]; customerRow["郵便番号"] = fields[5]; customerRow["住所"] = fields[6]; customerRow["会社名"] = fields[7]; dataTable.Rows.Add(customerRow); if (adapter.Update(dataTable) < 0) (6) { Console.WriteLine("作成でエラーが発生しました。"); } }
やや複雑に見えますが、基本的な構造はIndex関数と同じです。
(1)からは、挿入する行のNo列の値を求めています。具体的には、SQLのMax関数を使用して、No列の最大値を+1して求めています。(2)では、関数引数に与えられた登録データ(CSV)を分割して、文字列の配列を取得しています。(3)はIndex関数と同様で、全行をDataTableに取り込んでいます。(4)からは、挿入コマンドを生成しています。SQLのINSERT文を生成した後、パラメータをParameters.Addメソッドで追加しています。
(5)からは、DataTableに新しい行を追加し、各列に(2)で作成した文字列を割り当てています。これで、追加する行が完成するので、最後にRows.AddメソッドでDataTableに追加します。(6)のUpdateメソッドで、DataTableへの追加をデータソース(CSVファイル)に反映します。戻り値が負の場合はエラーメッセージを出力しています。アプリをビルドして、コマンドラインパラメータを例えば以下のように指定して実行し、CSVファイルを確認するか全データ出力を試してみて、新しい行が追加されていればCreate関数は正しく動作しています。
c ",NewName,NewKana,NewMail,NewTel,NewZip,NewAddress,NewCompany"
データ削除(Delete)を実装してみる
最後に、データ削除のDelete関数を紹介します。
void Delete(C1CSVConnection conn, long sno) { var adapter = new C1CSVDataAdapter(conn, $"SELECT * FROM customer WHERE [No] = {sno}"); (1) var dataTable = new DataTable(); adapter.Fill(dataTable); adapter.DeleteCommand = new C1CSVCommand(conn); (2) adapter.DeleteCommand.CommandText = "DELETE FROM customer WHERE [No] = @no"; adapter.DeleteCommand.Parameters.Add("@no", "No"); var customerRow = dataTable.Rows[0]; (3) customerRow.Delete(); if (adapter.Update(dataTable) < 0) (4) { Console.WriteLine("削除でエラーが発生しました。"); } }
こちらも、基本的な構造はIndex関数、Create関数と同じです。(1)では、削除対象の行をDataTableに取り込んでいます。Index関数、Create関数と異なり、処理対象の行を特定するときの記述となります(Read関数、Update関数でも同様です)。(2)からは、削除コマンドを生成しています。SQLのDELETE文を生成した後、パラメータをParameters.Addメソッドで追加しています。
(3)からは、DataTableから0番目の行(すなわち削除対象の行)を削除しています。2行に分けていますが、dataTable.Rows[0].Delete()としても同様です。(4)のUpdateメソッドで、DataTableでの削除をデータソース(CSVファイル)に反映します。戻り値が負数の場合はエラーメッセージを出力しています。アプリをビルドして、コマンドラインパラメータを例えば以下のように指定して実行し、CSVファイルを確認するか全データ出力を試してみて、No=20である行が削除されていればDelete関数は正しく動作しています。
d 20
まとめ
今回は、CSVデータをComponentOne Data Servicesを使って操作する事例を紹介しました。従来のADO.NETにおける手順とほとんど変わらず、静的なデータを利用できることをお伝えできたのではないかと思います。
次回は、このアプリを一括処理に対応させて、Data Servicesが大量のデータの処理にも対応できることを紹介します。また、Entity Framework連携によるモデル指向のデータ操作を、Windows Formsアプリを作成する事例を通じて紹介します。