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

  • A+
所属分类:C#

将DataRow转换成相应的对象(通用以及泛型操作) - jasen.kin - 博客园
  一直以来对框架非常感兴趣,对大多数框架(目前本人看过的)来说一般分为三个部分:
(1):拼接SQL语句(反射)。
(2):执行CRUD操作,获取相应的DataTable、DataSet等等。
(3):将相应的DataTable、DataSet转换成对象(反射)。

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

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

1561333462229_37.gif
 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(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();
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     }
1561333462229_37.gif

以上的代码主要是针对将DataRow转换成相应的对象,方法为
(1)public static object ToEntity(DataRow adaptedRow, Type entityType)
(2)public static T ToEntity(DataRow adaptedRow, T value) where T:new()

(二)Activator 类
对于Activator 类,主要为以下3个比较常用,包括对object和T的对象实例化。
1        public sealed class Activator : _Activator
2        {
3           public static T CreateInstance();
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 主要有以下几个常用的方法,如下:
1561333462229_37.gif
 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     }
1561333462229_37.gif

还有一个比较重要的属性:public abstract string Name { get; }
以上对象相应的方法的实例和运用请参考MSDN。
(四)相关的单元测试如下:
以上的2个主要方法的单元测试如下:
1561333462229_37.gif
 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         /// 

14         ///ToEntity 的测试
15          ///

16         [TestMethod()]
17         public void ToEntityGenericTest()
18         {
19             Information information = CreateNewItem();
20             DataRow adaptedRow = CreateNewDataRow(information);
21

22             Information actual = (Information)Mapper.ToEntity(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         }
1561333462229_37.gif

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

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

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin