データベースにアクセスするクラスを作ってみた(その2)
データベースにアクセスするクラスを変更しました。
主な変更点としては
- テーブル参照の結果をレコードのリストとして取得(レコードのリストの中には項目のデータのリストが入っています。)、
- SELECT COUNTなどの集計値を取得するメソッドを追加
- テーブルにアクセスするときの共通メソッドの作成
※3について
C#ではメソッドへの参照を保持することができます。(デリゲートといいます。) 具体的には、メソッド内にメソッドを定義でき、任意の場所で実行することができます。今回はこれを利用しました。
以下プログラムです。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Data.SqlServerCe; namespace TableAccess { class DBAccess { string connection_str; ////////コンストラクタ//////// public DBAccess(string dsrc, string pwrd){ // データベース接続用文字列の作成 connection_str = "Data Source = " + dsrc + "; Password ='" + pwrd + "'"; } ////////集計値確認(SELECT COUNT文など)//////// public int CountTable(string str) { int cnt = new Int32(); /*** テーブルアクセス呼び出し、戻り値を返す **/ bool result = AccessTable(str, (c) => { try { // 集計値確認 cnt = (int)c.ExecuteScalar(); return true; } catch (Exception) { return false; } }); if (result == false) return -1; return cnt; } ////////テーブル更新(UPDATE、INSERT、DELETE文など)//////// public bool RenewalTable(string str) { /*** テーブルアクセス呼び出し、戻り値を返す **/ return AccessTable(str, (c) => { try { // テーブル更新 c.ExecuteNonQuery(); return true; } catch (Exception) { return false; } }); } ////////テーブル参照(SELECT文など)//////// public List<object> ReferTable(string str) { List<object> records = null; try { /*** 複数レコードリストを生成 ***/ records = new List<object>(); /*** テーブルアクセス呼び出し***/ bool result = AccessTable(str, (c) => { // データリストを生成 List<string> item_values = new List<string>(); // データ読み込みストリーム生成 SqlCeDataReader scdr = c.ExecuteReader(); // 読み込むレコードが無くなるまで、次のレコードへ移動 while (scdr.Read()) { Func<List<string>> func = ()=> { List<string> v = new List<string>(); for (int i = 0; i < scdr.FieldCount -1; i++) v.Add(scdr.GetString(i)); return v; }; records.Add(func()); } // データ読み込みストリームを閉じる scdr.Close(); return true; }); if (result == false) throw new ApplicationException(); /*** レコードを返す***/ return records; } catch (Exception) { return null; } } ////////テーブルアクセス//////// private bool AccessTable(string str,Func<SqlCeCommand, bool> func) { SqlCeConnection conn = null; SqlCeCommand cmd = null; try { /*** データベースに接続 ***/ conn = new SqlCeConnection(connection_str); conn.Open(); /*** SQL文実行 ***/ cmd = conn.CreateCommand(); cmd.CommandText = str; bool r = func(cmd); if (r == false) throw new ApplicationException(); return true; } catch (Exception) { return false; } finally { if ( cmd != null) cmd.Dispose(); if (conn != null) conn.Close(); } } } // ここから下はDBAccessオブジェクトを生成して、実際にメソッドを実行 class Program { static void Main(string[] args) { // DBAccessオブジェクト生成 DBAccess dba = new DBAccess("dbfile3.sdf", "password123"); // テーブル更新 Console.WriteLine("テーブル更新します。"); bool result1; result1 = dba.RenewalTable("INSERT INTO 電話帳テーブル ([名前], [メールアドレス],[電話番号]) Values('うううう', 'bbbb.jp', '2222-2222')"); if (result1 == false) { Console.WriteLine("テーブル更新に失敗しました。"); Console.ReadLine(); return; } Console.WriteLine("\n\n\n"); // 集計値確認 Console.WriteLine("集計値確認を行います。"); int result2; result2 = dba.CountTable("SELECT COUNT(*) FROM 電話帳テーブル"); if (result2 < 0) { Console.WriteLine("集計値確認に失敗しました。"); Console.ReadLine(); return; } Console.WriteLine(result2); Console.WriteLine("\n\n\n"); // テーブル参照 Console.WriteLine("テーブル参照します。"); List<object> records = dba.ReferTable("SELECT * FROM 電話帳テーブ"); if (records == null) { Console.WriteLine("テーブル参照に失敗しました。"); Console.ReadLine(); return; } string out_line; foreach (List<string> r in records) { out_line = ""; foreach (string data in r) out_line += data + ","; Console.WriteLine("{0}\n", out_line); } Console.WriteLine("\n\n\n"); Console.ReadLine(); records.Clear(); return; } } }
実際にテーブルにアクセスするメソッドはAccessTableです。AccessTableの引数は以下のようにしました。
AccessTable(string str,Func<SqlCeCommand, bool> func)
第一引数(str)はSQL文,第二引数(func)がデリゲートです。型がFunc
bool r = func(cmd);
では、このfuncはどこで定義されているかというと、CountTableメソッド、RenewalTableメソッド、ReferTableメソッドのAccessTable呼び出し時です。例えば、CountTableメソッドでは以下のように呼び出しています。
return AccessTable(str, (c) => { try { // テーブル更新 c.ExecuteNonQuery(); return true; } catch (Exception) { return false; } });
(c) => {...};という部分がそうです。(改行が入っていて分かりにくいですが) これはラムダ式といって、デリゲートを定義できます。cは引数になります。(任意の文字でcでなくてもかまいません。)
また、ReferTableメソッドの以下個所においても、デリゲートを使用しています。
// 読み込むレコードが無くなるまで、次のレコードへ移動 while (scdr.Read()) { Func<List<string>> func = ()=> { List<string> v = new List<string>(); for (int i = 0; i < scdr.FieldCount -1; i++) v.Add(scdr.GetString(i)); return v; }; records.Add(func()); }
1レコード内の個々のstringのデータをListに追加し、そのListを取得レコード全体としてのList(records)に追加するという処理を「records.Add(func());」という個所で行っています。func()の定義は「Func> func = ()=> {...}」のラムダ文で行っています。