0

我正在寻找为生产服务器创建数据库行到对象映射器。

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

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

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

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

用途:

  

    /* 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 解决方案——我的理解是它不是一个战略性的长期解决方案(对于未来的实现、支持等不太灵活——更容易但不是真正的企业级)。我想保持对数据库映射层的控制,同时减少生产服务器未来开发中出现的故障。

你们如何看待这个实施,实现我的目标的最佳方式是什么?

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

墨菲斯

4

1 回答 1

1

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

(一位已经完成 DAL 框架的人的一点建议。

  1. 不要这样做。每种选择和风格都有很多可用的框架。如果您不喜欢 Entity Framework 或 nHibernate 等成熟的 ORM - 将光照映射器用作 Dapper 或 BLToolkit。否则你会花太多时间发明自己的自行车,而且很可能你还是会弄错。
  2. 如果您仍想这样做,请计划实施 LINQ,因为它是(对于开发人员)构建类型安全查询的最简单方法。
  3. 如果您仍然想要它,请不要强制您的“实体”类从您预定义的基类(DbMappableClass在您的情况下)继承。它打破了设计,打破了分层,打破了简单性。)
于 2012-07-24T18:31:46.617 回答