chiname

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

CN.Text开发笔记—利用反射将数据读入实体类

在实际开发中,我们经常需要从数据库中读取数据并赋值给实体类的相应属性。在.Text的DataDTOProvider中存在大量这样的代码, 比如:

public Role[] GetRoles(int BlogID)
        
{
            System.Collections.ArrayList al
=new System.Collections.ArrayList();
            IDataReader reader
=DbProvider.Instance().GetRoles(BlogID);
            
try
            
{
                
while(reader.Read())
                
{
                    Role role
=new Role();
                    
if(reader["RoleID"]!=DBNull.Value)
                    
{
                        role.RoleID
=(int)reader["RoleID"];
                    }

                    
if(reader["Name"]!=DBNull.Value)
                    
{
                        role.Name
=(string)reader["Name"];
                    }

                    
if(reader["Description"]!=DBNull.Value)
                    
{
                        role.Description
=(string)reader["Description"];
                    }

                    
//ReaderToObject(reader,role);
                    al.Add(role);
                }

            }

            
finally
            
{
                reader.Close();
            }

            
return (Role[])al.ToArray(typeof(Role));
        
        }


对于上面的代码,我觉得有几点不优雅之处:
1、每次对Role的属性进行赋值时,都要检查reader的值是否为DBNull,出现了很多重复代码
2、每次对Role的属性进行赋值时,都要进行类型转换, 而Role属性的类型是已知的,是不是可以自动完成这样的转换?
3、每次对Role的属性进行赋值时,都要进行Role属性与数据库字段的对应。如果我们在设计数据库与实体类时,保证数据库字段与实体类属性采用同样的名称,那利用反射,我们可以通过代码自动进行属性与字段的对应。即使数据库字段与属性不同名,我们也可以通过更改查询语句,来做到这一点。
是不是可以对上面的代码进行改进,使代码变得更优雅?那优雅的代码应该是什么样的呢?如果我们用上面代码中注释的代码行ReaderToObject(reader,role);取代它之前的对Role属性进行赋值的语句,是不是会使代码变得更优雅?ReaderToObject的作用就是自动完成将reader中的值写入到role中对应的属性中(前提是reader中的字段与role中对应的属性具有相同的名称)。现在我们的任务就是实现ReaderToObject, 有了强大的武器—Reflection,我们的任务就变得很轻松, 也不多说了,下面的代码是我的实现方法:

private void ReaderToObject(IDataReader reader,object targetObj)
        
{
            
for(int i=0;i<reader.FieldCount;i++)
            
{
                System.Reflection.PropertyInfo propertyInfo
=targetObj.GetType().GetProperty(reader.GetName(i));
                
if(propertyInfo!=null)
                
{
                    
if(reader.GetValue(i)!=DBNull.Value)
                    
{
                        propertyInfo.SetValue(targetObj,reader.GetValue(i),
null);
                    }

                }

            }

        }

ReaderToObject可以将reader中的数据读入到任何实体类中。数据库字段与实体类属性的映射原则是名称相同。当然,我们也可以通过配置文件来进行两者映射。

    个人想法:在开发中,面对那么多设计思想和设计模式,常常令人感到迷惑,当你把更多的精力放在选用哪个设计思想或设计模式时,我觉得不要忽略很重要的一点,尽可能地减少重复代码,只要我们能有效地减少重复代码,我们采用的方法就是好方法,而不要太在乎采用了哪种模式。就像独孤九剑,正因为摆脱了传统招式的束缚,才能战无不胜!

Feedback

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-12 18:14 by JGTM'2004 [MVP]
在敏捷实践中,重构是编码与设计过程中最重要的技术之一了,而模式是大方向(这背后还有一些OOAD的大原则,我会在最近的文章中联系起来阐述一下)——虽然23种模式中没有你用到的这一种,但是面向元数据的开发中确实也有一些(可能尚未成文的)模式——比如说你这段代码,在我之前写的ElegantDAL子系统中就几乎相同的出现过(这里我提示你处理Enum类型的时候需要绕一些小弯路,因为在数据库中一般是存为int或varchar的,这在SetValue的时候会出问题的——不过还是先留给你自己探索吧,不然多没乐趣呀!:)。

Great job. And enjoy coding!

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-12 18:51 by 吕震宇
@ JGTM'2004 [MVP]

哈哈,是不是在这里:

http://blog.joycode.com/jgtm2000/archive/2004/02/18/13294.aspx

正在读。“面向元数据的开发”,这背后含义颇多呀!很有启发性!

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-12 20:48 by wayfarer
一直期待dudu能把.Text的开发心得写出来,现在终于等到了,不顶不行啊:) 不过,更希望能有个系列,而非以这种散列化的方式表现出来。

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-12 21:09 by dudu
谢谢JGTM'2004 [MVP] 的指点。
Enum的确存在你所说的问题,参考你的文章:.NET Quick Tip: Runtime Type Conversion for Enumeration ,现在我将ReaderToObject代码改成这样:
private void ReaderToObject(IDataReader reader,object targetObj)
        
{
            
for(int i=0;i<reader.FieldCount;i++)
            
{
                System.Reflection.PropertyInfo propertyInfo
=targetObj.GetType().GetProperty(reader.GetName(i));
                
if(propertyInfo!=null)
                
{
                    
if(reader.GetValue(i)!=DBNull.Value)
                    
{
                        
if(propertyInfo.PropertyType.IsEnum)
                        
{
                            propertyInfo.SetValue(targetObj,Enum.ToObject(propertyInfo.PropertyType,reader.GetValue(i)),
null);
                        }

                        
else
                        
{
                            propertyInfo.SetValue(targetObj,reader.GetValue(i),
null);
                        }

                    }

                }

            }

        }

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-12 21:28 by dudu
@wayfarer
我会尽力在开发CN.Text过程中多写一些心得。

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-13 02:02 by lonelystranger
CN.Text这个名字起得不错

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-13 04:25 by kwklover
@dudu
用这中方法做的程序在性能上怎么样?

第一种,也就是你认为不优雅的和第二中优雅的方法在性能上有差别吗?差别多大?

能不能做一下分析呢?
谢谢

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-13 08:34 by jiezhi
反射能不用就不用,反射会有比较大的代价

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-13 09:25 by engine
to 楼上:
反射代价很大吗?只是给对象设置公共属性,会生产多大代价???
作者认为呢?!

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-13 15:43 by lion
很好的技巧,只是觉得对性能上的拖累太多

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-14 08:39 by jiezhi
to engine :
使用反射的性能是最差的。这个不需要我多言了吧

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-14 09:43 by longzx
csopf是一个C# Object Persistent Framework,可以参考一下,  

2004-09-14 10:02 by dudu
反射对性能的影响是勿容置疑的, 但我们不能因为这个原因就拒绝使用反射, 我们需要知道反射对性能的影响究竟多大, 使用反射是否利大于弊?请看一下这篇文章, 该文章对反射对性能的影响进行了分析与测试:
http://west-wind.com/weblog/posts/351.aspx
我们不能完全从性能的解度去考虑是否采用一项技术, 如果这样的话, 我们为什么不直接用汇编, 为什么还会有那么多高级语言, 为什么还会出现虚拟机?

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2004-09-30 15:09 by yoonkit
Thanks longzx for the recommendation.
I use reflection to extract the metadata of the class so that the mapping to the rdbms is transparent to the developer.

However I have also introduced a MetaInfo class which caches the reflection, so everytime we access the properties, it doesnt go through reflection but goes through the meta-info which has already been extracted.

This has a small performance hit over direct props/fields, but the hit is largely minimal, and the benefits to the maintenance to the code far outweighs the so called performance loss.

Feedback is truly welcomed!

yoonkit.

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2005-01-18 15:57 by exhjw
good!

不能因为汽车会有尾汽排出而拒绝乘坐

# re: CN.Text开发笔记—利用反射将数据读入实体类   

2005-08-15 15:16 by 小鸡鸡憋住==鸡憋
我在最近的项目开发中也用了楼上所讨论的技术,即自动DATASET对象(暂时只支持DATASET对象,没有DATAREADER)将内容读取到实体类,而且可以自动创建外键对象(比如一个订单主体有多笔明细这样)。。。

结论是反射所消耗的资源是非常巨大的,读取1000笔的主从记录(测试用),消耗了将近10秒的时间,估计这个速度在比较频繁的应用应该是会被客户干操的...所以我的建议是,用SINGLETON方式来保存实体类,然后在系统启动的初始化阶段利用工作线程来读取记录。
posted on 2005-10-09 16:39  把我的欢乐带给你  阅读(396)  评论(0)    收藏  举报