タグ別アーカイブ: .net

System.Data.DataModel.BaseModel




さて、今週の課題が一段落しました。
まぁ使われるかどうかはわからないけど、バグは出るのは承知。
System.Data.DataModelという名前空間に
BaseModelと言うクラスを作りました。
インターフェイスとか継承とかしてたら、
思いのほか重くなって、当初の想定より
パフォーマンスは出ないみたいです。
でも、プログラムはきれいになって、
メンテもしやすそうだからよしとしましょう。
プロパティに値を代入する部分については(この148行目あたり)
プロパティ名と同じ名前のテーブル列を直接指定することも考えました。
しかし大文字、小文字、実際存在しない列名もあるかもしれないと言う
エラーを回避するために、foreachでプロパティ名とテーブルの列名をぶつけて
同名の物があれば代入する形を取りました。(ってToLower()してるじゃん!)

これを派生したモデルクラスを生成して、
プロパティとCRUDのSQL、接続文字列を設定すれば、
モデルクラスオブジェクトのリスト、モデルクラスオブジェクトの取得、
オブジェクトのデータベースへの格納、編集、削除が可能となります。
以下、モデルクラスの実装方法。超簡単でしょ?
(TestID, TestNameというプロパティを持つTestDataクラス)

    class TestData : BaseModel
    {

        private string selectAllString = 
                            "Select TestID, TestName From TestData";
        private string selectString = 
                            "Select TestID, TestName From TestData Where TestID = @TestID";
        private string insertString = 
                            "Insert Into TestData(TestName) Values(@TestName)";
        private string updateString = 
                            "Update TestData Set TestName = @TestName Where TestID = @TestID";
        private string deleteString = 
                            "Delete From TestData Where TestID = `@TestID";

        public TestData()
        {

            string connectionString;
            ConsoleApplication1.Properties.Settings set 
               = new ConsoleApplication1.Properties.Settings();
            connectionString = set.LunchConnectionString;
            this.dbController = DbController.DbControllerFactory
                            (DataProvider.SqlClient, connectionString);
            this.dbController.SelectAllCommand = this.selectAllString;
            this.dbController.SelectCommand = this.selectString;
            this.dbController.InsertCommand = this.insertString;
            this.dbController.UpdateCommand = this.updateString;
            this.dbController.DeleteCommand = this.deleteString;
        }

        public int TestID { get; set; }
        public string TestName { get; set; }
    }

まぁ、一番の難点はSQLのデバッグってことでしょうかね。
んで、実際に呼ぶプログラムは以下のような感じです。


            Console.WriteLine("Select ALL MyClass");
            var my1 = new System.DataModel.TestData();
            //全データ取得
            var myData1 = my1.GetAll();
            foreach (System.DataModel.TestData data in myData1)
            {
                Console.WriteLine("ID: {0} / Name: {1}", data.TestID, data.TestName);
            }
            
            Console.WriteLine("Insert MyClass");
            var my2 = new System.DataModel.TestData();
            my2.TestName = "Insert MyClass";
            //新規追加
            my2.Insert("TestID"); //TestIDはTestDataの主キー


            Console.WriteLine("Selec MyClass");
            var my3 = new System.DataModel.TestData();
            //主キーからモデルオブジェクトを取得
            my3.TestID = 3;
            my3.GetData("TestID");
            sw.Stop();
            Console.WriteLine("ID: {0} / Name: {1}", my3.TestID, my3.TestName);           

            Console.WriteLine("Update MyClass");
            //更新
            my3.TestName = "Change MyClass" + DateTime.Now.ToString();
            my3.Update();

最終的にはGUIでプロパティを設定して、ポチッとボタンを押したら、
テーブル追加、クラスファイル生成、CRUDのSQL生成までできるといいなぁと妄想中。
とりあえずパーツはできたので、実際にASP.NET MVCに適用して見ることにします。
えっと、夏休みは今月いっぱいだから。。。名古屋はやっぱり行けないか

ソースはこちらからダウンロードできます。

自作モジュールその1

さて使えるかどうかわからないけど、自分でプログラムを作成してみました。
ASP.NET MVCのモデルでADO.NET Entity Data Modelを使うと簡単にモデルを構成できるのですが、
これOracleでは使えないっぽいんですね。
(私の調査不足かもしれないのであしからず。ちなみにMySQLはできそうです。)
実際にViewで表示する場合、DataTableは使えないらしく、
IEnumerable型じゃないとだめとの事。
「普通にDataTableをforeachして変換すればいいんじゃない」
と思ってたのですが、どうせやるなら汎用的に使えるものをと取り掛かってみました。
モデルの親クラス(DataModeler)を作成。

    public enum DataProvider{
        SqlClient = 1,
        OracleClient = 2
        
    }
    class DataModeler : IDataModeler
    {
        public IEnumerable GetAll(object type)
        {
            DataSet ds = new DataSet();
            this.adapter.SelectCommand.CommandText = this.selectCommand;
            this.adapter.Fill(ds);
            
            List list = new List(); 
            
            foreach(DataRow row in ds.Tables[0].Rows)
            {
                Type t = type.GetType();
                var data = Activator.CreateInstance(type.GetType());
                foreach (DataColumn column in ds.Tables[0].Columns)
                {
                    foreach (PropertyInfo property in t.GetProperties())
                    {
                        if (column.ColumnName.ToLower() == property.Name.ToLower())
                        {
                            property.SetValue(data, row[column.ColumnName], null);
                            break;
                        }
                    }
                }
                list.Add(data);
               
            }
            return list;   
        }
 
        private string selectCommand;

        public string SelectCommand
        {
            get { return selectCommand; }
            set { selectCommand = value; }
        }

        protected IDbDataAdapter adapter;


        public DataModeler(DataProvider dataProvider)
        {
            switch (dataProvider)
            {
                case DataProvider.SqlClient:
                    this.adapter = 
                             new System.Data.SqlClient.SqlDataAdapter();
                    this.adapter.SelectCommand = 
                             new System.Data.SqlClient.SqlCommand();
                    this.adapter.SelectCommand.Connection = 
                             new System.Data.SqlClient.SqlConnection();
                    break;
                case DataProvider.OracleClient:
                    this.adapter = 
                             new Oracle.DataAccess.Client.OracleDataAdapter();
                    this.adapter.SelectCommand = 
                             new Oracle.DataAccess.Client.OracleCommand();
                    this.adapter.SelectCommand.Connection = 
                             new Oracle.DataAccess.Client.OracleConnection();
                    break;
            }           
        }

        public DataModeler()
        {
        }

        public void SetConnectionString(string connectinoString)
        {
            this.adapter.SelectCommand.Connection.ConnectionString = connectinoString;
        }

ここでデータベースとのやり取りをしてやればいいなと考えたわけです。
基本的な考えはTableAdapter。
まずは一覧を取得したいということで、GetAllというメソッドだけ作ってみました。
プロパティ名と列名をぶつけるところがもっときれいにできればよかったのですが、
現状、私の知識だとここまでが精一杯というところです。
んでこのDataModelerを派生させたモデルクラスを用意します。
(よく見るNWINDを使っています、はい)

  class TestModel : DataModeler
    {
        public int ProductID { get; set; }

        public string ProductKana { get; set; }

        public string ProductName { get; set; }

        public int SupplierID { get; set; }

        public int CategoryID { get; set; }

        public string QuantityPerUnit { get; set; }

        public object UnitPrice { get; set; }

        public int UnitsInStock { get; set; }

        public int UnitisOnOrder { get; set; }

        public int ReorderLevel { get; set; }

        public object Discontinued { get; set; }

        public TestModel(DataProvider dataProvider):base(dataProvider)
        {
        }

        public TestModel()
        {
        }
    }

んで実際にこれを使ってプログラムを実行してみます。

    class Program
    {
        static void Main(string[] args)
        {
            System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();

            sw.Start();
            string connect = @"****************";
            string select = "Select * From Products";

            TestModel test = new TestModel(DataProvider.SqlClient);
            test.SetConnectionString(connect);
            test.SelectCommand = select;
            var pro2 = test.GetAll(test);
            foreach (TestModel data in pro2)
            {
                Console.Write(data.CategoryID);
            }
            Console.WriteLine();
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
            sw.Reset();

            sw.Start();
            MyEntities db = new MyEntities();
            var pro1 = from b in db.Products select b;
            foreach (var data in pro1)
            {
                Console.Write(data.CategoryID);
            }
            Console.WriteLine();
            sw.Stop();
            Console.WriteLine(sw.ElapsedMilliseconds);
            //Console.ReadKey();
           
            Console.ReadKey();
            
        }
    }

呼び出しのためのコードは現状3倍くらいですが、もっと簡素化できると思います。
あと、クラス作るの大変ですが、実行速度はADO.NET Entity Data Modelを使ったときに比べてかなり早くなっています。



でもよく考えるとDataAdapter使っているから普通にグリッドビューと
SQLデータソースを使ったほうが間違いなくパフォーマンスはいいはず。
まぁあとこれを今後使うかどうかは生産性次第というところ。(MVCでやるかということも含め)
とりあえず今日の実績ということで。

C#.NET LINQ

@ITのInsider.NET、C#3.0入門までやってみました。
http://www.atmarkit.co.jp/fdotnet/csharp30/index/index.html
前述の通り、知らない機能が沢山あって衝撃の嵐。
あのときに使えたら!という物もちらほらと。

個人的にプログラミング自体かなりブランクがあったので
確かにいい勉強にはなりました。
LINQは面白いですね。
オブジェクトの操作をSQLっぽくできるという点は特に。
列挙に入れて、検索もびしばしやれますよ。
しかしですね、そもそも今まで列挙をそんなに使う開発なんかしてたっけ?
DBの出し入れがメインの業務アプリではあんまりないような気がしないでもないけど、
まぁ密かに、チャンスを見つけて使っていきたいと思います。
オマケとしてはLINQの学習でラムダ式もちょくちょく出て来て、
こちらの理解度もちょっとは上がった模様。
まだまだ奥は深いC#の世界ですが、
とりあえず3.0までメインとなる機能を触る事ができるようになったので
これくらいにして明日は違う事をやる予定。
とりあえず、画面系の勉強でもしますかってJQueryかな。。。

という事で、今回学んだ事列挙。ってタグづけもするけどね
Oracle 11gインストール
Oracle 11gクライアント設定
Oracle 11gユーザーの作成
ODP.netでOracleの操作
Generic
匿名メソッド
デリゲート
ラムダ式
型推論
var
コレクション初期化子
匿名クラス
拡張メソッド
LINQ

後は忘れないようにたまに復習もせな。