将DataRow转换成相应的对象(通用以及泛型操作)

  一直以来对框架非常感兴趣,对大多数框架(目前本人看过的)来说一般分为三个部分:

(1):拼接SQL语句(反射)。

(2):执行CRUD操作,获取相应的DataTable、DataSet等等。

(3):将相应的DataTable、DataSet转换成对象(反射)。

因此可以将上述3个部分各个击破,一步一步来实现自己的框架,看的框架多了,也就成了路。反射在这里面被淋漓尽致的运用,哈哈,站在款哥的肩膀上......

 

(一)通用以及泛型转换代码

先看下面关于将DataRow转换成相应的对象(通用以及泛型操作)的方法(这里仅仅是对DataRow进行转换,对于将DataTable转换成对象集合,思路基本差不多,因此本例里不再对其他的进行相关代码的编写):

 1     public class Mapper
 2     {
 3         public static object ToEntity(DataRow adaptedRow, Type entityType)
 4         {
 5             if (entityType == null || adaptedRow == null)
 6             {
 7                 return null;
 8             }
 9 
10             object entity = Activator.CreateInstance(entityType);
11             CopyToEntity(entity, adaptedRow);
12 
13             return entity;
14         }
15 
16         public static T ToEntity<T>(DataRow adaptedRow, T value) where T:new()
17         {
18             T item = new T();
19             if (value == null || adaptedRow == null)
20             {
21                 return item;
22             }
23 
24             item = Activator.CreateInstance<T>();
25             CopyToEntity(item, adaptedRow);
26 
27             return item;
28         }
29 
30         public static void CopyToEntity(object entity, DataRow adaptedRow)
31         {
32             if (entity == null || adaptedRow == null)
33             {
34                 return;
35             }
36             PropertyInfo[] propertyInfos = entity.GetType().GetProperties();
37 
38             foreach (PropertyInfo propertyInfo in propertyInfos)
39             {
40                 if (!CanSetPropertyValue(propertyInfo, adaptedRow))
41                 {
42                     continue;
43                 }
44 
45                 try
46                 {
47                     if (adaptedRow[propertyInfo.Name] is DBNull)
48                     {
49                         propertyInfo.SetValue(entity, nullnull);
50                         continue;
51                     }
52                     SetPropertyValue(entity, adaptedRow, propertyInfo);
53                 }
54                 finally
55                 {
56 
57                 }
58             }
59         }
60 
61         private static bool CanSetPropertyValue(PropertyInfo propertyInfo, DataRow adaptedRow)
62         {
63             if (!propertyInfo.CanWrite)
64             {
65                 return false;
66             }
67 
68             if (!adaptedRow.Table.Columns.Contains(propertyInfo.Name))
69             {
70                 return false;
71             }
72 
73             return true;
74         }
75 
76         private static void SetPropertyValue(object entity, DataRow adaptedRow, PropertyInfo propertyInfo)
77         {
78             if (propertyInfo.PropertyType == typeof(DateTime?||
79                 propertyInfo.PropertyType == typeof(DateTime))
80             {
81                 DateTime date = DateTime.MaxValue;
82                 DateTime.TryParse(adaptedRow[propertyInfo.Name].ToString(),
83                     CultureInfo.CurrentCulture, DateTimeStyles.None, out date);
84 
85                 propertyInfo.SetValue(entity, date, null);
86             }
87             else
88             {
89                 propertyInfo.SetValue(entity, adaptedRow[propertyInfo.Name], null);
90             }
91         }
92     }

 

 

以上的代码主要是针对将DataRow转换成相应的对象,方法为

(1)public static object ToEntity(DataRow adaptedRow, Type entityType)
(2)public static T ToEntity<T>(DataRow adaptedRow, T value) where T:new()

 

(二)Activator 类

对于Activator 类,主要为以下3个比较常用,包括对object和T的对象实例化。

1        public sealed class Activator : _Activator
2        {
3           public static T CreateInstance<T>(); 
4           public static object CreateInstance(Type type);
5           public static object CreateInstance(Type type, params object[] args);
6        }

 


(三)PropertyInfo的灵活运用

一般情况下,我们会对PropertyInfo进行灵活运用,以达到相应的目标,这是大家惯用的伎俩,哈哈。

 

先根据Type.GetProperties()获取该类型的所有属性,返回为属性数组PropertyInfo[]。

 PropertyInfo[] propertyInfos = entity.GetType().GetProperties();

然后对PropertyInfo[] 进行相应的操作。

 

相应的PropertyInfo 主要有以下几个常用的方法,如下:

 1     public abstract class PropertyInfo : MemberInfo, _PropertyInfo
 2     {
 3         public static bool operator !=(PropertyInfo left, PropertyInfo right);
 4         public static bool operator ==(PropertyInfo left, PropertyInfo right);
 5 
 6         public abstract bool CanRead { get; }
 7         public abstract bool CanWrite { get; }
 8         public abstract Type PropertyType { get; }
 9 
10         public virtual object GetValue(object obj, object[] index);
11         public abstract object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture);
12 
13         public virtual void SetValue(object obj, object value, object[] index);
14         public abstract void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture);
15     }

 

还有一个比较重要的属性:public abstract string Name { get; }

以上对象相应的方法的实例和运用请参考MSDN。

(四)相关的单元测试如下:

以上的2个主要方法的单元测试如下:

 1         [TestMethod()]
 2         public void ToEntityTest()
 3         {
 4             Information information = CreateNewItem();
 5 
 6             DataRow adaptedRow = CreateNewDataRow(information);
 7             Type entityType = typeof(Information);
 8             Information actual = (Information)Mapper.ToEntity(adaptedRow, entityType);
 9 
10             AssertInformationState(information, actual);
11         }
12        
13         /// <summary>
14         ///ToEntity<T> 的测试
15          ///</summary>
16         [TestMethod()]
17         public void ToEntityGenericTest()
18         {
19             Information information = CreateNewItem();
20             DataRow adaptedRow = CreateNewDataRow(information);
21            
22             Information actual = (Information)Mapper.ToEntity<Information>(adaptedRow,information);
23 
24             AssertInformationState(information, actual);
25         }
26 
27         private static void AssertInformationState(Information information, Information actual)
28         {
29             Assert.IsNotNull(actual);
30             Assert.IsNull(actual.Address);
31             Assert.IsNull(actual.Region);
32             Assert.AreEqual(information.Id, actual.Id);
33             Assert.AreEqual(information.Name, actual.Name);
34             Assert.AreEqual(information.CreateDate, actual.CreateDate);
35         }
36 
37         private static Information CreateNewItem()
38         {
39             Information information = new Information()
40             {
41                 Id = 0,
42                 Name = "Jasen",
43                 CreateDate = DateTime.Now,
44                 Region = null
45             };
46 
47             return information;
48         }
49 
50         private DataRow CreateNewDataRow(Information information)
51         {
52             DataTable table= CreateTempTable();
53             DataRow row= table.NewRow();
54 
55             row["Name"= information.Name;
56             row["CreateDate"= information.CreateDate;
57             table.Rows.Add(row);
58 
59             return table.Rows[0];
60         }
61 
62         private DataTable CreateTempTable()
63         {
64             DataTable namesTable = new DataTable("Temp");
65 
66             DataColumn idColumn = new DataColumn();
67             idColumn.DataType = System.Type.GetType("System.Int32");
68             idColumn.ColumnName = "id";
69             idColumn.AutoIncrement = true;
70             namesTable.Columns.Add(idColumn);
71 
72             DataColumn nameColumn = new DataColumn();
73             nameColumn.DataType = System.Type.GetType("System.String");
74             nameColumn.ColumnName = "Name";
75             nameColumn.DefaultValue = "Name";
76             namesTable.Columns.Add(nameColumn);
77 
78             DataColumn createDateColumn = new DataColumn();
79             createDateColumn.DataType = System.Type.GetType("System.DateTime");
80             createDateColumn.ColumnName = "CreateDate";
81             namesTable.Columns.Add(createDateColumn);
82 
83             DataColumn regionColumn = new DataColumn();
84             regionColumn.DataType = System.Type.GetType("System.String");
85             regionColumn.ColumnName = "Region";
86             namesTable.Columns.Add(regionColumn);
87 
88             DataColumn[] keys = new DataColumn[1];
89             keys[0= idColumn;
90             namesTable.PrimaryKey = keys;
91  
92             return namesTable;
93         }

 

 

以上的2处标识红色的代码段为主要的验证逻辑,代码应该比较清晰以及简单,故本人不会讲解其中的代码。

 

总的来说,对于将DataRow转换成相应的对象或者泛型,主要是通过反射来进行操作的。以前也看到过很多别人写的相关类似的功能,不过很多都是不怎么好的,BUG无数.......莫名其妙的,哈哈,跟款哥混了一阵,也开始偶尔对代码眼光挑剔了,近朱者赤,近墨者黑,还真是这么一回事。以前做个什么,只要基本功能实现了,谁还去管它呢!现在代码改个几遍,依旧还是会仔细去看、去想,尽量会去考虑各种情况。现在发现自己变了,哈哈.....

 

源代码下载:DataRow转换成对象源代码下载

 
posted @ 2011-02-15 00:37  jasen.kin  阅读(13183)  评论(25编辑  收藏  举报