一直以来对框架非常感兴趣,对大多数框架(目前本人看过的)来说一般分为三个部分:
(1):拼接SQL语句(反射)。
(2):执行CRUD操作,获取相应的DataTable、DataSet等等。
(3):将相应的DataTable、DataSet转换成对象(反射)。
因此可以将上述3个部分各个击破,一步一步来实现自己的框架,看的框架多了,也就成了路。反射在这里面被淋漓尽致的运用,哈哈,站在款哥的肩膀上......
(一)通用以及泛型转换代码
先看下面关于将DataRow转换成相应的对象(通用以及泛型操作)的方法(这里仅仅是对DataRow进行转换,对于将DataTable转换成对象集合,思路基本差不多,因此本例里不再对其他的进行相关代码的编写):
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, null , null );
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的对象实例化。
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 主要有以下几个常用的方法,如下:
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个主要方法的单元测试如下:
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转换成对象源代码下载