使用CodeDom提高ORM性能
下载本文代码:http://www.cnblogs.com/Files/afritxia2008/WebTest.rar(请使用 Visual Studio 2008 打开)
在进行讨论之前,我假设读者已经了解.NET反射、自定义属性、CodeDom这些技术。并接触过ORM框架源码,如果对ORM并不了解,可以参考:http://www.cnblogs.com/xdesigner/archive/2008/06/24/1228702.html。在这篇文章中,我们主要讨论通过CodeDom提高ORM读取数据的性能问题。
ORM(Object/Relation Mapping对象–关系数据库映射)其中的一个功能是将数据源数据赋值给实体。实现方法是利用自定义属性和.NET反射机制。例如:
2 {
3 /// <summary>
4 /// 获取或设置留言 ID
5 /// </summary>
6 [DataColumn(ColumnName = "LWordUID")]
7 public int LWordUID
8 {
9 //
10 }
11
12 /// <summary>
13 /// 获取或设置发送用户
14 /// </summary>
15 [DataColumn(ColumnName = "PostUser")]
16 public string PostUser
17 {
18 //
19 }
20
21 /// <summary>
22 /// 获取或设置发送时间
23 /// </summary>
24 [DataColumn(ColumnName = "PostTime")]
25 public DateTime PostTime
26 {
27 //
28 }
29
30 /// <summary>
31 /// 获取或设置文本内容
32 /// </summary>
33 [DataColumn(ColumnName = "TextContent")]
34 public string TextContent
35 {
36 //
37 }
38 }
DataColumn是自定义的属性类,代码并不复杂所以在这里也就省略了。接下来需要通过反射读取自定义属性,并赋值。代码如下:
2 {
3 // 获取实体类型
4 Type objType = objEntity.GetType();
5
6 // 获取属性信息
7 PropertyInfo[] propInfoList = objType.GetProperties();
8
9 if (propInfoList == null || propInfoList.Length <= 0)
10 return;
11
12 foreach (PropertyInfo propInfo in propInfoList)
13 {
14 object[] colAttrList = propInfo.GetCustomAttributes(typeof(DataColumnAttribute), false);
15
16 // 未标记 DataColumn 属性
17 if (colAttrList == null || colAttrList.Length <= 0)
18 continue;
19
20 // 获取数据列属性
21 DataColumnAttribute colAttr = colAttrList[0] as DataColumnAttribute;
22
23 int ordinal = –1;
24
25 try
26 {
27 // 获取数据列序号
28 ordinal = dr.GetOrdinal(colAttr.ColumnName);
29 }
30 catch (Exception ex)
31 {
32 throw new MappingException(
33 String.Format("{0} 未找到该数据列( Cannot Found this Column {0} )", colAttr.ColumnName), ex);
34 }
35
36 // 获取数据列值
37 object objValue = dr.GetValue(ordinal);
38
39 if (objValue is DBNull)
40 {
41 // 将 null 值设置到属性
42 propInfo.SetValue(objEntity, null, null);
43 }
44 else
45 {
46 // 将值设置到属性
47 propInfo.SetValue(objEntity, objValue, null);
48 }
49 }
50 }
51
以上代码实现 了读取数据源数据并向实体赋值的功能。但这样做速度非常慢,因为每读取一条数据库记录,每读取一个数据字段并向实体赋值的时候,都必须进行一次反射操作。 数据量越大,且数据字段或实体属性越多,那么速度就越慢!在以上代码中,对实体的反射操作,其目的就是赋值。可以被等价的语句所替代:
entity.Prop = dr[“Porp”];
用简单的赋值语句肯定要比反射的速度快很多,而大数据量和多数据库字段对其影响也不是很大。不过需要注意的是因为每一个实体的具体属性不相同,所以赋值过程也是不相同的。例如:
News实体赋值代码:
2 {
3 // 新闻 ID
4 entity.ID = (int)dr["ID"];
5 // 标题
6 entity.Title = (string)dr["Title"];
7 // 摘要
8 entity.Summary = (string)dr["Summary"];
9 // 发送用户
10 entity.PostUser = (string)dr["PostUser"];
11 // 发送时间
12 entity.PostTime = (DateTime)dr["PostTime"];
13 // 文本内容
14 entity.TextContent = (string)dr["TextContent"];
15 }
User实体赋值代码:
2 {
3 // 用户 ID
4 entity.ID = (int)dr["ID"];
5 // 用户名称
6 entity.UserName = (string)dr["UserName"];
7 // 密码
8 entity.UserPass = (string)dr["UserPass"];
9 // 电子邮件
10 entity.EMail = (string)dr["EMail"];
11 // 注册时间
12 entity.RegisterTime = (DateTime)dr["RegisterTime"];
13 }
14
News与User所具备的属性不同,所以赋值过程,也不相同!但毫无疑问,使用直接赋值的方法是速度最快的!试想一下,假如在做反射的时候不是直接赋值,而是根据自定义属性,动态的生成赋值代码,编译以后临时保存起来。那么以后再进行赋值操作的时候,直接调用这个编译好的赋值代码,不就可以大大提升程序性能了么?有没有一个办法可以自动建立类似上面这样的代码呢?我们可以考虑使用反射和CodeDom技术。
首先为了解决不同实体的不同的赋值过程,我们需要建立一个接口:IEntityPropertyPutter。在该接口中的PutEntityProperties函数负责真正的赋值逻辑。在赋值的过程中会调用IEntityPropertyPutter的具体实现类的实例。具体类图如下:
EntityPropertyPutterFactory工厂类负责创建IEntityPropertyPutter接口具体实现类的实例。首先该工厂类会从缓存中获取IEntityPropertyPutter接口实例,如果该实例为空(还没有被创建),那么该工厂类会调用EntityPropertyPutterMaker构建者类创建实例(Entity实体类本身也可以直接实现IEntityPropertyPutter接口,来加快程序的运行速度)。在构建者内部会动态创建新的程序集(Assembly),在该程序集中只存在一个QuicklyPutter类。在QuicklyPutter类中描述了具体的赋值逻辑,这些逻辑编码则是根据反射和CodeDom完成的。最后交由CodeDom动态编译……根据不同的实体,所创建的程序集也不相同。所编译成功的程序集是临时存放在内存里,所以QuicklyPutter类用白色表示。具体代码如下:
2using System.Collections.Generic;
3using System.Data.Common;
4using System.Reflection;
5
6using Net.AfritXia.Data.Mapping;
7
8namespace Net.AfritXia.Data
9{
10 partial class SQLHelper
11 {
12 public void PutEntityProperties<T>(T entity, DbDataReader dr) where T : class
13 {
14 // 获取设置器
15 IEntityPropertyPutter<T> putter = EntityPropertyPutterFactory.Create<T>(entity, this.IncludeDebugInformation);
16
17 if (putter == null)
18 throw new NullReferenceException(@"设置器为空( Null Putter )");
19
20 try
21 {
22 // 设置实体属性
23 putter.PutEntityProperties(entity, dr);
24 }
25 catch (Exception ex)
26 {
27 string errorMessage = null;
28
29 // 定义异常信息格式
30 errorMessage = @"从数据库字段{0} 读取值并赋给属性{1} 时出错(实体类型: {2})";
31 // 格式化信息
32 errorMessage = String.Format(errorMessage, putter.CurrentDBColName, putter.CurrentPropName, putter.EntityTypeName);
33
34 // 抛出异常
35 throw new Exception(errorMessage, ex);
36 }
37 }
38 }
39}
40
设置器工厂类EntityPropertyPutterFactory:
2using System.Collections;
3using System.Reflection;
4
5namespace Net.AfritXia.Data
6{
7 /// <summary>
8 /// 实体属性设置器工厂类
9 /// </summary>
10 internal sealed class EntityPropertyPutterFactory
11 {
12 // 设置器字典
13 private static readonly Hashtable g_putterHash = Hashtable.Synchronized(new Hashtable());
14
15 /// <summary>
16 /// 创建实体属性设置器
17 /// </summary>
18 /// <typeparam name="T">实体类型模版</typeparam>
19 /// <param name="fromEntity">实体</param>
20 /// <param name="includeDebugInfo">是否包含调试信息</param>
21 /// <returns></returns>
22 public static IEntityPropertyPutter<T> Create<T>(T fromEntity, bool includeDebugInfo) where T : class
23 {
24 if (fromEntity == null)
25 return null;
26
27 // 如果实体本身已经实现了 IEntityPropertyPutter<T> 接口,
28 // 则直接返回
29 if (fromEntity is IEntityPropertyPutter<T>)
30 return (IEntityPropertyPutter<T>)fromEntity;
31
32 IEntityPropertyPutter<T> putter = null;
33
34 // 获取字典关键字
35 string hashKey = fromEntity.GetType().FullName;
36
37 if (g_putterHash.ContainsKey(hashKey))
38 {
39 // 从字典中获取设置器
40 putter = g_putterHash[hashKey] as IEntityPropertyPutter<T>;
41 }
42 else
43 {
44 EntityPropertyPutterMaker maker = null;
45
46 // 创建构建器
47 maker = new EntityPropertyPutterMaker();
48 // 是否包含调试信息
49 maker.IncludeDebugInformation = includeDebugInfo;
50
51 // 新建应用程序集
52 putter = maker.Make<T>();
53 // 保存应用设置器到字典
54 g_putterHash.Add(hashKey, putter);
55 }
56
57 return putter;
58 }
59 }
60}
构建器EntityPropertyPutterMaker:
2
3using System;
4using System.CodeDom;
5using System.Collections.Specialized;
6using System.CodeDom.Compiler;
7using System.Data.Common;
8#if _Debug
9using System.IO;
10#endif
11using System.Reflection;
12
13using Microsoft.CSharp;
14
15using Net.AfritXia.Data.Mapping;
16
17namespace Net.AfritXia.Data
18{
19 /// <summary>
20 /// 构建实体属性设置器
21 /// </summary>
22 internal sealed class EntityPropertyPutterMaker
23 {
24 // 默认名称空间
25 private const string DefaultNamespace = "Net.AfritXia.Data._AutoCode";
26 // QuicklyPutter 类名称
27 private const string QuicklyPutterClassName = "QuicklyPutter";
28
29 // 包含调试信息
30 private bool m_includeDebugInfo = false;
31
32 类构造器
40
41 /// <summary>
42 /// 设置或获取是否包含调试信息
43 /// </summary>
44 public bool IncludeDebugInformation
45 {
46 set
47 {
48 this.m_includeDebugInfo = value;
49 }
50
51 get
52 {
53 return this.m_includeDebugInfo;
54 }
55 }
56
57 /// <summary>
58 /// 构建实体属性设置器
59 /// </summary>
60 /// <typeparam name="T">实体类型模版</typeparam>
61 /// <returns></returns>
62 public IEntityPropertyPutter<T> Make<T>() where T : class
63 {
64 // 创建一个可编译的单元
65 CodeCompileUnit compileUnit = this.MakeCompileUnit();
66 // 创建名称空间
67 CodeNamespace namespace_code = this.MakeNamespace();
68 // 定义类
69 CodeTypeDeclaration class_code = this.MakeClass<T>();
70 // 创建 PutEntityProperties 方法
71 CodeMemberMethod method_code = this.MakeMethod<T>();
72
73 // 添加方法到类
74 class_code.Members.Add(method_code);
75 // 添加类到名称空间
76 namespace_code.Types.Add(class_code);
77 // 添加名称空间到编译单元
78 compileUnit.Namespaces.Add(namespace_code);
79
80 // 创建 C# 编译器
81 CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
82 // 创建编译参数
83 CompilerParameters options = new CompilerParameters();
84
85 // 添加对 System.dll 的引用
86 options.ReferencedAssemblies.Add("System.dll");
87 // 添加对 System.Data.dll 的引用
88 options.ReferencedAssemblies.Add("System.Data.dll");
89 // 添加对该项目的引用
90 options.ReferencedAssemblies.Add(this.GetType().Assembly.Location);
91 // 添加对实体项目的引用
92 options.ReferencedAssemblies.Add(typeof(T).Assembly.Location);
93 // 只在内存中编译
94 options.GenerateInMemory = true;
95
96#if _Debug
97 string srcFilePath = null;
98
99 srcFilePath = @"C:\{0}_{1}.cs";
100 srcFilePath = String.Format(srcFilePath, typeof(T).Name, QuicklyPutterClassName);
101
102 // 源文件输出流
103 StreamWriter srcOutput = new StreamWriter(srcFilePath, false);
104 // 写出源文件
105 provider.GenerateCodeFromCompileUnit(compileUnit, srcOutput, new CodeGeneratorOptions());
106
107 srcOutput.Flush();
108 srcOutput.Close();
109#endif
110
111 // 编译并获取编译结果
112 CompilerResults compileResult = provider.CompileAssemblyFromDom(options, compileUnit);
113
114 // 编译失败则抛出异常
115 if (compileResult.NativeCompilerReturnValue != 0)
116 throw new Exception("编译失败 ( Compile Failed )");
117
118 // 创建设置器
119 object putter = compileResult.CompiledAssembly.CreateInstance(DefaultNamespace + "." + QuicklyPutterClassName);
120
121 return (IEntityPropertyPutter<T>)putter;
122 }
123
124 /// <summary>
125 /// 构建可编译单元
126 /// </summary>
127 /// <returns></returns>
128 private CodeCompileUnit MakeCompileUnit()
129 {
130 // 创建一个可编译的单元
131 return new CodeCompileUnit();
132 }
133
134 /// <summary>
135 /// 构建名称空间
136 /// </summary>
137 /// <returns></returns>
138 private CodeNamespace MakeNamespace()
139 {
140 // 创建名称空间
141 return new CodeNamespace(DefaultNamespace);
142 }
143
144 /// <summary>
145 /// 构建 QuicklyPutter 类
146 /// </summary>
147 /// <returns></returns>
148 private CodeTypeDeclaration MakeClass<T>() where T : class
149 {
150 // 定义 QuicklyPutter 类
151 CodeTypeDeclaration class_code = new CodeTypeDeclaration(QuicklyPutterClassName);
152
153 // 令该类实现 IEntityPropertyPutter<T> 接口
154 class_code.BaseTypes.Add(typeof(IEntityPropertyPutter<T>));
155
156 // 添加 EntityTypeName 属性
157 class_code = this.MakeEntityTypeNameProperty<T>(class_code);
158 // 添加 CurrentPropName 属性
159 class_code = this.MakeCurrentPropNameProperty(class_code);
160 // 添加 CurrentDBColName 属性
161 class_code = this.MakeCurrentDBColNameProperty(class_code);
162
163 return class_code;
164 }
165
166 /// <summary>
167 /// 构建 EntityTypeName 属性
168 /// </summary>
169 /// <typeparam name="T">实体类型模版</typeparam>
170 /// <param name="targetClass">目标代码</param>
171 /// <returns></returns>
172 private CodeTypeDeclaration MakeEntityTypeNameProperty<T>(CodeTypeDeclaration targetClass) where T : class
173 {
174 if (targetClass == null)
175 throw new ArgumentNullException("targetClass");
176
177 /*
178 * 以下代码将生成
179 *
180 * public string EntityTypeName
181 * {
182 * get
183 * {
184 * return 实体类型名称字符串
185 * }
186 * }
187 *
188 *
189 */
190
191 // EntityTypeName 属性
192 CodeMemberProperty entityTypeNameProp_code = null;
193
194 // 创建属性
195 entityTypeNameProp_code = new CodeMemberProperty();
196 // 定义为公共属性
197 entityTypeNameProp_code.Attributes = MemberAttributes.Public;
198 // 返回字符串类型
199 entityTypeNameProp_code.Type = new CodeTypeReference(typeof(string));
200 // 属性名称
201 entityTypeNameProp_code.Name = "EntityTypeName";
202 // 返回语句
203 entityTypeNameProp_code.GetStatements.Add(
204 new CodeMethodReturnStatement(new CodePrimitiveExpression(typeof(T).Name)));
205
206 // 添加属性到类
207 targetClass.Members.Add(entityTypeNameProp_code);
208
209 return targetClass;
210 }
211
212 /// <summary>
213 /// 构建 CurrentPropName 属性
214 /// </summary>
215 /// <param name="targetClass">目标类代码</param>
216 /// <returns></returns>
217 private CodeTypeDeclaration MakeCurrentPropNameProperty(CodeTypeDeclaration targetClass)
218 {
219 if (targetClass == null)
220 throw new ArgumentNullException("targetClass");
221
222 /*
223 * 以下代码将生成
224 *
225 * private string m_currPropName;
226 *
227 * public string CurrentPropName
228 * {
229 * get
230 * {
231 * return this.m_currPropName;
232 * }
233 * }
234 *
235 */
236
237 // 变量名称
238 const string VaribleName = "m_currPropName";
239
240 // m_currPropName
241 CodeMemberField m_currPropName_code = null;
242
243 // 创建字段
244 m_currPropName_code = new CodeMemberField();
245 // 定义为私有成员
246 m_currPropName_code.Attributes = MemberAttributes.Private;
247 // 创建变量
248 m_currPropName_code = new CodeMemberField(typeof(string), VaribleName);
249
250 // 添加成员到类
251 targetClass.Members.Add(m_currPropName_code);
252
253 // CurrentPropName
254 CodeMemberProperty currPropName_code = null;
255
256 // 创建属性
257 currPropName_code = new CodeMemberProperty();
258 // 定义为公共属性
259 currPropName_code.Attributes = MemberAttributes.Public;
260 // 返回字符串类型
261 currPropName_code.Type = new CodeTypeReference(typeof(string));
262 // 属性名称
263 currPropName_code.Name = "CurrentPropName";
264 // get 返回语句
265 currPropName_code.GetStatements.Add(
266 new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), VaribleName)));
267
268 // 添加属性到类
269 targetClass.Members.Add(currPropName_code);
270
271 return targetClass;
272 }
273
274 /// <summary>
275 /// 构建 CurrentDBColName 属性
276 /// </summary>
277 /// <param name="targetClass">父级类</param>
278 /// <returns></returns>
279 private CodeTypeDeclaration MakeCurrentDBColNameProperty(CodeTypeDeclaration targetClass)
280 {
281 if (targetClass == null)
282 throw new ArgumentNullException("targetClass");
283
284 /*
285 * 以下代码将生成
286 *
287 * private string m_currDBColName;
288 *
289 * public string CurrentDBColName
290 * {
291 * get
292 * {
293 * return this.m_currDBColName;
294 * }
295 * }
296 *
297 */
298
299 // 变量名称
300 const string VaribleName = "m_currDBColName";
301 // m_currDBColName
302 CodeMemberField m_currDBColName_code = null;
303
304 // 创建字段
305 m_currDBColName_code = new CodeMemberField();
306 // 定义为私有成员
307 m_currDBColName_code.Attributes = MemberAttributes.Private;
308 // 创建变量
309 m_currDBColName_code = new CodeMemberField(typeof(string), VaribleName);
310
311 // 添加成员到类
312 targetClass.Members.Add(m_currDBColName_code);
313
314 // CurrentDBColName
315 CodeMemberProperty currDBCol_code = null;
316
317 // 创建属性
318 currDBCol_code = new CodeMemberProperty();
319 // 定义为公共属性
320 currDBCol_code.Attributes = MemberAttributes.Public;
321 // 返回字符串类型
322 currDBCol_code.Type = new CodeTypeReference(typeof(string));
323 // 属性名称
324 currDBCol_code.Name = "CurrentDBColName";
325 // get 返回语句
326 currDBCol_code.GetStatements.Add(
327 new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "m_currDBColName")));
328
329 // 添加属性到类
330 targetClass.Members.Add(currDBCol_code);
331
332 return targetClass;
333 }
334
335 /// <summary>
336 /// 构建 PutEntityProperties 方法
337 /// </summary>
338 /// <typeparam name="T"></typeparam>
339 /// <param name="fromEntity"></param>
340 /// <returns></returns>
341 private CodeMemberMethod MakeMethod<T>() where T : class
342 {
343 // PutObjectProperties 方法
344 CodeMemberMethod method_code = null;
345
346 // 创建方法
347 method_code = new CodeMemberMethod();
348 // 定义为公共方法
349 method_code.Attributes = MemberAttributes.Public;
350 // 返回类型
351 method_code.ReturnType = new CodeTypeReference(typeof(void));
352 // 方法名称
353 method_code.Name = "PutEntityProperties";
354 // 添加参数 entity
355 method_code.Parameters.Add(new CodeParameterDeclarationExpression(typeof(T), "entity"));
356 // 添加参数 dr
357 method_code.Parameters.Add(new CodeParameterDeclarationExpression(typeof(DbDataReader), "dr"));
358
359 // 获取实体类型
360 Type objType = typeof(T);
361
362 // 获取 DataTable 属性标记
363 object[] tabAttrList = objType.GetCustomAttributes(typeof(DataTableAttribute), false);
364
365 if (tabAttrList == null || tabAttrList.Length <= 0)
366 {
367 throw new MappingException(
368 String.Format(@"类 {0} 未标记 DataTable 属性 ( Unlabeled [DataTable] Attribute On Class {0} )", objType.Name));
369 }
370
371 // 获取属性信息
372 PropertyInfo[] propInfoList = objType.GetProperties();
373
374 if (propInfoList == null || propInfoList.Length <= 0)
375 return null;
376
377 foreach (PropertyInfo propInfo in propInfoList)
378 {
379 object[] colAttrList = propInfo.GetCustomAttributes(typeof(DataColumnAttribute), false);
380
381 // 未标记 DataColumn 属性
382 if (colAttrList == null || colAttrList.Length <= 0)
383 continue;
384
385 // 获取数据列属性
386 DataColumnAttribute colAttr = colAttrList[0] as DataColumnAttribute;
387
388 // 创建方法内容
389 method_code = this.MakeMethodContent(method_code, propInfo, colAttr, this.IncludeDebugInformation);
390 }
391
392 return method_code;
393 }
394
395 /// <summary>
396 /// 构建 PutEntityProperties 方法内容
397 /// </summary>
398 /// <param name="targetMethod"></param>
399 /// <param name="prop"></param>
400 /// <param name="attr"></param>
401 /// <param name="includeDebugInfo"></param>
402 /// <returns></returns>
403 private CodeMemberMethod MakeMethodContent(CodeMemberMethod targetMethod, PropertyInfo prop, DataColumnAttribute attr, bool includeDebugInfo)
404 {
405 if (targetMethod == null)
406 throw new ArgumentNullException("targetMethod");
407
408 if (attr == null)
409 throw new ArgumentNullException("attr");
410
411 // 实体变量名称 entity
412 string varEntityName = targetMethod.Parameters[0].Name;
413 // 数据源变量名称 dr
414 string varDrName = targetMethod.Parameters[1].Name;
415
416 // entity 属性名称
417 string varEntityPropName = String.Format(@"{0}.{1}", varEntityName, prop.Name);
418 // dr 属性名称
419 string varDrPropName = String.Format(@"{0}[""{1}""]", varDrName, attr.Name);
420
421 // 创建变量
422 CodeVariableReferenceExpression entityProp_code = new CodeVariableReferenceExpression(varEntityPropName);
423 // 创建值
424 CodeVariableReferenceExpression dr_code = new CodeVariableReferenceExpression(varDrPropName);
425
426 // 包含调试信息
427 if (includeDebugInfo)
428 {
429 // this.m_currPropName = entity.Prop
430 targetMethod.Statements.Add(new CodeAssignStatement(
431 new CodeVariableReferenceExpression("this.m_currPropName"),
432 new CodePrimitiveExpression(prop.Name)));
433
434 // this.m_currDBColName = attributeName
435 targetMethod.Statements.Add(new CodeAssignStatement(
436 new CodeVariableReferenceExpression("this.m_currDBColName"),
437 new CodePrimitiveExpression(attr.Name)));
438 }
439
440 if (attr.IsNullable)
441 {
442 /*
443 * 以下代码生成的是条件判断代码
444 *
445 * if (dr[""] != DBNull.Value) {
446 * entity.Prop = dr[""];
447 * }
448 *
449 */
450
451 CodeConditionStatement if_code = new CodeConditionStatement();
452
453 // if (dr[""] != DBNull.Value)
454 if_code.Condition = new CodeBinaryOperatorExpression(
455 new CodeVariableReferenceExpression(varDrPropName),
456 CodeBinaryOperatorType.IdentityInequality,
457 new CodeVariableReferenceExpression("System.DBNull.Value"));
458
459 // entity.Prop = dr[""];
460 if_code.TrueStatements.Add(new CodeAssignStatement(
461 entityProp_code,
462 new CodeCastExpression(prop.PropertyType, dr_code)));
463
464 targetMethod.Statements.Add(if_code);
465 }
466 else
467 {
468 // entity.Prop = dr[""];
469 targetMethod.Statements.Add(new CodeAssignStatement(
470 entityProp_code,
471 new CodeCastExpression(prop.PropertyType, dr_code)));
472 }
473
474 return targetMethod;
475 }
476 }
477}
代码时序图如下:
具体代码可以参考:
Net.AfritXia.Data/IEntityPropertyPutter.cs
Net.AfritXia.Data/EntityPropertyPutterFactory.cs
Net.AfritXia.Data/EntityPropertyPutterMaker.cs
TestProj/UnitTest_Putter.cs(可以运行该测试文件)