泛型类成员填充问题(datarow-to-object mapper)(高效解决方案)

时间:2012-07-24 18:20:54

标签: c# generics orm accessor system.reflection

我希望为生产服务器创建一个数据库行到对象映射器。

我的目标是在一个位置填充数据库列名称,以及该对象的字段,以存储从数据库查询返回的单个行。

我打算稍后添加功能来自动获取表名和连接字符串。这样做的目的是集中所有与数据库相关的东西(自动跟踪列和查询字符串的命名,添加对返回结果的保护,错误记录等)。

我读了很多关于泛型集访问器的想法,以为我目前无法从中合成解决方案。

这是我想要实现的(非工作)骨架。欢迎所有评论,关于优化和更好的做法。

利用率:

  

    /* 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
        }
    }

如何通过ReadObject()通常填充指定的字段(Uid,Type,IpAddr等)?我需要一个等同于指向成员的指针...我也读过关于反射但我不确定效率并且不理解100%如何实现它。

注意:我宁愿不使用完整的ORM解决方案 - 我的理解是它不是一个长期的解决方案(对于未来的实施,支持等不太灵活 - 更容易但不是真正的企业级)。我希望保持对db映射层的控制,同时减少生产服务器上未来开发中出现的毛刺。

你们对这个实现有什么看法,以及实现目标的最佳方法是什么?

感谢您的时间,并致以最诚挚的问候,

睡眠

1 个答案:

答案 0 :(得分:1)

你的猜测是正确的:你将不得不使用反射。

(一位已经完成DAL框架分享的人的一些建议。

  1. 不要这样做。每种选择和风味都有很多可用的框架。如果您不喜欢像Entity Framework或nHibernate这样的完整ORM,请使用轻型映射器作为Dapper或BLToolkit。否则你会花太多时间发明自己的自行车,很可能你仍然会弄错。
  2. 如果您仍想这样做,请计划实施LINQ,因为这是构建类型安全查询的最简单方法(开发人员)。
  3. 如果仍然想要它,请不要强制您的“实体”类继承您预定义的基类(在您的情况下为DbMappableClass)。它打破了设计,打破了分层,打破了简洁。)