VisualStudio2005を使ってるが、
「型付DataSet」にはいろいろ不満がある。
自動的に作られるのはいいけど、
接続文字列まで内部に持ってたり、
時々壊れて、XSDビューで開けなかったり、
TableAdapterに書き込んだクエリの
メンテナンスをしようと思うと、
いちいち、重たいXSDビューを開かなくてはならずイライラする。
また、TableAdapterを必死につくったのに、DBスキーマの変更があったときには結局コンバートできず
ウィザードやら、プロパティビューやらをこつこつ叩いて作り直した。
メモリ上のデータの保存場所としても普通のDataTableのほうが使いやすい。
例えば、一意制約が邪魔になることも多かった。
正直、もう2度とごめんだとおもった。
(たとえ、僕の作り方が悪かったんだとしても。。。)
ただ、データを型付きのオブジェクトで扱えるのは嬉しい。
結局、1行分のDataRowをオブジェクトにマッピングできれば、
十分、型付であることメリットは得られる。
リフレクション使えば、以下の程度の仕様の型付Rowはできそうだ。
これによって、データの型変換を省力化でき、コード補完によってカラムを思い出せる。
以下の「DataTableUtil.cs」がORMと呼べる部分のすべてだ。
あとは、DBカラムと同じフィールドを持つPOJO(ここでは「User.cs」)を作ればおしまい。
■DataTableUtil.cs
using System; using System.Collections.Generic; using System.Text; using System.Data; using System.Reflection; namespace DataSet { class DataTableUtil<T> where T : new() { DataTable dt; private int cursor = 0; public DataTableUtil(DataTable dt) { this.dt = dt; } public T GetRowData(int rowIndex) { T rowObject = new T(); Type objType = rowObject.GetType(); FieldInfo[] fis = objType.GetFields(); foreach (FieldInfo fi in fis) { fi.SetValue(rowObject, dt.Rows[rowIndex][fi.Name]); } return rowObject; } public T NextRow() { T ret = GetRowData(cursor); cursor++; return ret; } public bool hasRow() { return (this.dt.Rows.Count != cursor); } } }
DBのカラムと同じフィールドを持つPojoを作る。
Propertyを使えばカプセル化もできるだろう。
(上記のDataTableUtilはプロパティには対応してないけど)
■User.cs
using System; using System.Collections.Generic; using System.Text; namespace DataSet { class User { public int ID; public String Name; public DateTime BirthDay; public Decimal Salary; } }
実験用アプリはWindows Formアプリでつくった。
button1_Clickが、上記の仕組みを使ったコード
button2_Clickは、ノーマルなDataTableを使う方法。
コード量はそんなに変わらないけど、
補完が効くので、実装上は効率アップが実感できた。
private DataTable createDatatable() { //////////////////////////// // データテーブルを作る //////////////////////////// DataTable dt = new DataTable(); dt.Columns.AddRange( new DataColumn[]{ new DataColumn("ID",typeof(Int32)), new DataColumn("Name",typeof(String)), new DataColumn("BirthDay",typeof(DateTime)), new DataColumn("Salary",typeof(Decimal)) }); // データ1件目 DataRow row1 = dt.NewRow(); row1["ID"] = "1"; row1["Name"] = "山本"; row1["BirthDay"] = new DateTime(1977, 5, 24); row1["Salary"] = 10; dt.Rows.Add(row1); // データ2件目 DataRow row2 = dt.NewRow(); row2["ID"] = "2"; row2["Name"] = "亀野"; row2["BirthDay"] = new DateTime(1978, 3, 23); row2["Salary"] = 20; dt.Rows.Add(row2); return dt; } private void button1_Click(object sender, EventArgs e) { DataTable dt = createDatatable(); DataTableUtil<User> util = new DataTableUtil<User>(dt); StringBuilder sb = new StringBuilder(); while (util.hasRow()) { User user = util.NextRow(); sb.AppendLine(user.ID + ":" + user.Name + ":" + user.BirthDay + ":" + user.Salary); } Console.WriteLine(sb.ToString()); } private void button2_Click(object sender, EventArgs e) { DataTable dt = createDatatable(); StringBuilder sb = new StringBuilder(); foreach (DataRow row in dt.Rows) { int id = (int)row["ID"]; string name = (String)row["Name"]; DateTime birthDay = (DateTime)row["BirthDay"]; Decimal salary = (Decimal)row["Salary"]; sb.AppendLine(id + ":" + name + ":" + birthDay + ":" + salary); } Console.WriteLine(sb.ToString()); }
ありがた迷惑で横柄なFWよりも、
車輪を再発明してでも、ちゃんと自分でコントロールできるほうがいい。