カスタム属性再び
カスタム属性の使い道としてデータベースのテーブルやカラム情報を持たせて一元管理したらどうかと、サンプルをこさえてみました。
using System; using System.Text; using System.Reflection; // 構造体のみ対象 // フィールドの順序が変わらないように・・・ [AttributeUsage(AttributeTargets.Struct)] public class DBTableAttribute : Attribute { private string name; private string tablespace; private int initial; private int next; private int maxextents; private int pctincrease; public DBTableAttribute() {} // テーブル名 // 指定しなければ型名になる public string Name { get { return name; } set { name = value; } } // テーブルスペース public string Tablespace { get { return tablespace; } set { tablespace = value; } } // INITIAL public int Initial { get { return initial; } set { initial = value; } } // NEXT public int Next { get { return next; } set { next = value; } } // MAXEXTENTS // 0の場合、UNLIMITED public int Maxextents { get { return maxextents; } set { maxextents = value; } } // PCTINCRESE public int Pctincrease { get { return pctincrease; } set { pctincrease = value; } } } // フィールドのみ対象 [AttributeUsage(AttributeTargets.Field)] public class DBColumnAttribute : Attribute { private string name; private int size; private bool nullable; public string Name { get { return name;} set { name = value; } } public int Size { get { return size; } set { size = value; } } public bool Null { get { return nullable; } set { nullable = value; } } } // カスタム属性の利用例 // DBTableAttribute属性からcreate文を生成する public class TableScriptCreator { public static string Create(Type type) { if (!type.IsDefined(typeof(DBTableAttribute), false)) return null; DBTableAttribute tabatt = type.GetCustomAttributes(typeof(DBTableAttribute), false)[0] as DBTableAttribute; string s, t; StringBuilder sb = new StringBuilder(); s = tabatt.Name != null ? tabatt.Name : type.Name; sb.AppendFormat("CREATE TABLE {0} (\n", s.ToUpper()); foreach (FieldInfo fi in type.GetFields()) { if (!fi.IsDefined(typeof(DBColumnAttribute), false)) continue; DBColumnAttribute colatt = fi.GetCustomAttributes(typeof(DBColumnAttribute), false)[0] as DBColumnAttribute; if (fi.FieldType == typeof(int)) { t = String.Format("NUMBER({0})", colatt.Size); } else if (fi.FieldType == typeof(DateTime)) { t = "DATE"; } else { t = String.Format("VARCHAR2({0})", colatt.Size); } s = (colatt.Name != null) ? colatt.Name : fi.Name; sb.AppendFormat("{0}{1}{2},\n", s.ToUpper().PadRight(12), t.PadRight(16), colatt.Null ? "NULL" : "NOT NULL"); } sb.Remove(sb.Length - 2, 1); sb.Append(")\n"); sb.AppendFormat("TABLESPACE {0} \n", tabatt.Tablespace); sb.AppendFormat("STORAGE(INITIAL {0} NEXT {1} MAXEXTENTS {2} PCTINCREASE {3});", tabatt.Initial, tabatt.Next, (tabatt.Maxextents > 0) ? tabatt.Maxextents.ToString() : "UNLIMITED", tabatt.Pctincrease); return sb.ToString(); } } // テスト用構造体 [DBTable(Name="UserMaster",Tablespace="USERS",Initial=1024*512,Next=1024*256,Maxextents=0,Pctincrease=0)] public struct User { // DB格納対象 [DBColumn(Size=10,Null=false)] public int id; [DBColumn(Name="FIRSTNAME",Size=32,Null=false)] public string first; [DBColumn(Name="LASTNAME",Size=32,Null=false)] public string last; [DBColumn(Size=8,Null=false)] public DateTime birth; [DBColumn(Size=255,Null=true)] public string email; // DB格納対象外 public DateTime loginTime; } public class App { public static void Main() { Console.WriteLine(TableScriptCreator.Create(typeof(User))); } } /* 結果 CREATE TABLE USERMASTER ( ID NUMBER(10) NOT NULL, FIRSTNAME VARCHAR2(32) NOT NULL, LASTNAME VARCHAR2(32) NOT NULL, BIRTH DATE NOT NULL, EMAIL VARCHAR2(255) NULL ) TABLESPACE USERS STORAGE(INITIAL 524288 NEXT 262144 MAXEXTENTS UNLIMITED PCTINCREASE 0); */
DBTableAttribute属性とDBColumnAttribute属性にデータベーステーブルを作るために必要な情報を持たせています。ユニークキーや外部キーなどの制約条件用のカスタム属性とかを用意したりすれば、結構使えそうな気がします。更にテーブルとオブジェクトのマッピングを行うクラスとか色々充実させていけば、一財産になりそーなんですが、仕事じゃ全く.NETを使う機会がないので、そこまで時間かけられないのが残念。うーん、.NETの開発やりたいです・・・
実際問題、世の中にはO/Rマッピングの優れたライブラリが沢山あるので、わざわざ自作しなくても良いのですが、個人的にこの手は好きなので、いつかやってしまいそう。作ったら会社に持っててみようかしら?(^^;