0

実稼働サーバー用のデータベースの行からオブジェクトへのマッパーを作成しようとしています。

私の目標は、データベースの列名を 1 つの場所に入力し、データベース クエリから返された 1 つの行をこのオブジェクトのどのフィールドに格納するかを指定することです。

後でテーブル名と接続文字列を自動的に取得する機能を追加する予定です。これを行う目的は、すべてのデータベース関連のものを一元化することです (列の名前付けとクエリ文字列が自動的に続き、返された結果に保護を追加し、エラー ログなど)。

現在、そこからソリューションを合成できないと考えているジェネリック セット アクセサーについてよく読んでいます。

これは、私が達成しようとしているものの(動作していない)スケルトンです。最適化とより良い実践についても、すべてのコメントを歓迎します。

利用 :

  

    /* get MediaInfo filled regarding CDbColumnFind criterias */
    CEventReportingMediaInfo MediaInfo = DbQuery(1, new CDbColumnFind() { Name = "uid", Value = "2" });

これがDb-Mappable基本クラスです

 

    public class DbMappableClass
    {
        /********************************************/
        /* required fields for database information */
        /********************************************/
        public string TableName;
        public IList TableColumns;

        /********************************************/
        /* generic object filling helper            */
        /********************************************/
        public void ReadObject(DataRow FromRow)
        {
            foreach (CDbColumn Column in TableColumns)
            {
                TryParseGeneric(FromRow[Column.Name].ToString(), Column.Field);
            }
        }

        /********************************************/
        /* conversion helper                        */
        /********************************************/
        public static bool TryParseGeneric(string src, T value)
        {
            TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));

            try
            {
                value = (T)converter.ConvertFromString(src);
                return true;
            }
            catch
            {
                value = default(T);
                CSysLog.WriteEntry(SysLogLevel.WARNING, "failed to convert src ({0}) to type ({1}), use default value ({2})", src.ToString(), typeof(T), value);
                return false;
            }
        }

        /********************************************/
        /* Db column type                           */
        /********************************************/
        public class CDbColumn
        {
            private readonly string name;
            private readonly SqlDbType sqltype;
            private readonly Type ctype;

            public CDbColumn(string Name, SqlDbType SqlType, object Field)
            {
                this.name = Name;
                this.sqltype = SqlType;
                this.Field = Field;
                this.ctype = Field.GetType();
            }

            public string Name { get { return name; } }
            public SqlDbType SqlType { get { return sqltype; } }
            public object Field { get; set; }
            public Type CType { get { return ctype; } }
        }

        /********************************************/
        /* Db Query type criterias                  */
        /********************************************/
        public class CDbColumnFind
        {
            public string Name;
            public object Value;
        }

        /********************************************/
        /* Generic Db Query                         */
        /********************************************/
        public static TReturnType DbQuery(int ExpectedCount, params CDbColumnFind[] Args) where TReturnType : DbMappableClass, new()
        {
            /* query database, obtain results in RowResults ... */

            TReturnType ReturnResult = new TReturnType();

            DataRow RowResults = TableResult.Rows[0];

            ReturnResult.ReadObject(RowResults);
        }
    }

db-mappable 派生オブジェクトのカスタムで一元化された宣言になりました

 

    /********************************************/
    /* Event Reporting Media Table : Database   */
    /********************************************/
    public class CEventReportingMediaInfo : DbMappableClass
    {
        /**********************************/
        /** Member Declaration          ***/
        /**********************************/
        public int          Uid     { get; set; }
        public MediaType    Type    { get; set; }
        public string       IpAddr  { get; set; }
        public Int32        Port    { get; set; }
        public MediaStatus  Status  { get; set; }
        public int          Delay   { get; set; }


        /**********************************/
        /** Database Informations       ***/
        /**********************************/
        public CEventReportingMediaInfo()
        {
            TableName = "event_reporting_media_tbl";

            TableColumns = new ReadOnlyCollection (new[] {
                    new CDbColumn ("uid"           , SqlDbType.Int,            Uid),
                    new CDbColumn ("media_type"    , SqlDbType.TinyInt,        Type),
                    new CDbColumn ("media_ip"      , SqlDbType.VarChar,        IpAddr),
                    new CDbColumn ("media_port"    , SqlDbType.Int,            Port),
                    new CDbColumn ("media_status"  , SqlDbType.TinyInt,        Status),
                    new CDbColumn ("media_delay"   , SqlDbType.Int,            Delay)
            });
        }

        public enum MediaType
        {
            INVALID = 0,
            SIP_GATEWAY = 1,
            MODEM = 2
        }

        public enum MediaStatus
        {
            OFFLINE = 0,
            ONLINE = 1
        }
    }

特定のフィールド (Uid、Type、IpAddr など) を一般的に ReadObject() で埋めるにはどうすればよいですか? メンバーへのポインターに相当するものが必要です...リフレクションについても読みましたが、効率についてはよくわからず、実装方法を100%理解していません。

注: 完全な ORM ソリューションを使用しないことをお勧めします。私の理解では、それは戦略的な長期的なソリューションではありません (将来の実装、サポートなどの柔軟性が低くなります。より簡単ですが、実際にはエンタープライズ グレードではありません)。本番サーバーでの将来の開発でグリッチの発生を減らしながら、db マッピング レイヤーの制御を維持したいと考えています。

この実装についてどう思いますか?私の目標を達成するための最良の方法は何ですか?

お時間をいただきありがとうございます。よろしくお願いいたします。

モーフィアス

4

1 に答える 1

1

あなたの推測は正しかった: Reflection を使用する必要があります。

(DAL フレームワークの分担を行ってきた男性からのちょっとしたアドバイス。

  1. やらないでください。あらゆる選択肢とフレーバーに利用できるフレームワークがたくさんあります。Entity Framework や nHibernate などの本格的な ORM が気に入らない場合は、Dapper または BLToolkit などのライト マッパーを使用してください。そうしないと、自分の自転車を発明するのに時間がかかりすぎて、おそらくまだ間違っているでしょう.
  2. それでもやりたい場合は、LINQ の実装を計画してください。LINQ は (開発者にとって) タイプ セーフなクエリを作成する最も簡単な方法だからです。
  3. それでもやりたい場合は、「エンティティ」クラスに事前定義された基本クラスからの継承を強制しないDbMappableClassでください(あなたの場合)。それはデザインを壊し、レイヤリングを壊し、シンプルさを壊します。)
于 2012-07-24T18:31:46.617 に答える