打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
使用CodeDom提高ORM性能 - Net.AfritXia - 博客园
userphoto

2008.07.07

关注

使用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读取数据的性能问题。

  ORMObject/Relation Mapping对象-关系数据库映射)其中的一个功能是将数据源数据赋值给实体。实现方法是利用自定义属性和.NET反射机制。例如:

 1
    public class LWordEntity
 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是自定义的属性类,代码并不复杂所以在这里也就省略了。接下来需要通过反射读取自定义属性,并赋值。代码如下:


 1
    public void PutEntityProperties(object objEntity, DbDataReader dr)
 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[0as 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, nullnull);
43
            }

44
            
else
45
            
{
46
                
// 将值设置到属性
47
                propInfo.SetValue(objEntity, objValue, null);
48
            }

49
        }

50
    }

51


  以上代码实现了读取数据源数据并向实体赋值的功能。但这样做速度非常慢,因为每读取一条数据库记录,每读取一个数据字段并向实体赋值的时候,都必须进行一次反射操作。数据量越大,且数据字段或实体属性越多,那么速度就越慢!在以上代码中,对实体的反射操作,其目的就是赋值。可以被等价的语句所替代:
    
entity.Prop = dr[“Porp”];
用简单的赋值语句肯定要比反射的速度快很多,而大数据量和多数据库字段对其影响也不是很大。不过需要注意的是因为每一个实体的具体属性不相同,所以赋值过程也是不相同的。例如:
News实体赋值代码:

 1
        void PutEntityProperties(NewsEntity entity, DbDataReader dr)
 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实体赋值代码:

 1
        void PutEntityProperties(UserEntity entity, DbDataReader dr)
 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

  NewsUser所具备的属性不同,所以赋值过程,也不相同!但毫无疑问,使用直接赋值的方法是速度最快的!试想一下,假如在做反射的时候不是直接赋值,而是根据自定义属性,动态的生成赋值代码,编译以后临时保存起来。那么以后再进行赋值操作的时候,直接调用这个编译好的赋值代码,不就可以大大提升程序性能了么?有没有一个办法可以自动建立类似上面这样的代码呢?我们可以考虑使用反射和CodeDom技术。




  首先为了解决不同实体的不同的赋值过程,我们需要建立一个接口:IEntityPropertyPutter。在该接口中的PutEntityProperties函数负责真正的赋值逻辑。在赋值的过程中会调用IEntityPropertyPutter的具体实现类的实例。具体类图如下:

 


  EntityPropertyPutterFactory工厂类负责创建IEntityPropertyPutter接口具体实现类的实例。首先该工厂类会从缓存中获取IEntityPropertyPutter接口实例,如果该实例为空(还没有被创建),那么该工厂类会调用EntityPropertyPutterMaker构建者类创建实例(Entity实体类本身也可以直接实现IEntityPropertyPutter接口,来加快程序的运行速度)。在构建者内部会动态创建新的程序集(Assembly),在该程序集中只存在一个QuicklyPutter类。在QuicklyPutter类中描述了具体的赋值逻辑,这些逻辑编码则是根据反射和CodeDom完成的。最后交由CodeDom动态编译……根据不同的实体,所创建的程序集也不相同。所编译成功的程序集是临时存放在内存里,所以QuicklyPutter类用白色表示。具体代码如下:

 1
using System;
 2
using System.Collections.Generic;
 3
using System.Data.Common;
 4
using System.Reflection;
 5

 6
using Net.AfritXia.Data.Mapping;
 7

 8
namespace 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:

 

 1
using System;
 2
using System.Collections;
 3
using System.Reflection;
 4

 5
namespace 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:

  1
#undef _Debug  // 用于调试
  2

  3
using System;
  4
using System.CodeDom;
  5
using System.Collections.Specialized;
  6
using System.CodeDom.Compiler;
  7
using System.Data.Common;
  8
#if _Debug
  9
using System.IO;
 10
#endif
 11
using System.Reflection;
 12

 13
using Microsoft.CSharp;
 14

 15
using Net.AfritXia.Data.Mapping;
 16

 17
namespace 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
            
194360docimg_501_            // 创建属性
195360docimg_502_            entityTypeNameProp_code = new CodeMemberProperty();
196360docimg_503_            // 定义为公共属性
197360docimg_504_            entityTypeNameProp_code.Attributes = MemberAttributes.Public;
198360docimg_505_            // 返回字符串类型
199360docimg_506_            entityTypeNameProp_code.Type = new CodeTypeReference(typeof(string));
200360docimg_507_            // 属性名称
201360docimg_508_            entityTypeNameProp_code.Name = "EntityTypeName";
202360docimg_509_            // 返回语句
203360docimg_510_            entityTypeNameProp_code.GetStatements.Add(
204360docimg_511_                new CodeMethodReturnStatement(new CodePrimitiveExpression(typeof(T).Name)));
205360docimg_512_
206360docimg_513_            // 添加属性到类
207360docimg_514_            targetClass.Members.Add(entityTypeNameProp_code);
208360docimg_515_
209360docimg_516_            return targetClass;
210360docimg_517_        }

211360docimg_518_
212360docimg_519_360docimg_520_        /// <summary>
213360docimg_521_        /// 构建 CurrentPropName 属性
214360docimg_522_        /// </summary>
215360docimg_523_        /// <param name="targetClass">目标类代码</param>
216360docimg_524_        /// <returns></returns>

217360docimg_525_        private CodeTypeDeclaration MakeCurrentPropNameProperty(CodeTypeDeclaration targetClass)
218360docimg_526_360docimg_527_        {
219360docimg_529_            if (targetClass == null)
220360docimg_530_                throw new ArgumentNullException("targetClass");
221360docimg_531_
222360docimg_532_360docimg_533_            /* 
223360docimg_534_             * 以下代码将生成
224360docimg_535_             * 
225360docimg_536_             * private string m_currPropName;
226360docimg_537_             * 
227360docimg_538_             * public string CurrentPropName 
228360docimg_539_             * {
229360docimg_540_             *     get
230360docimg_541_             *     {
231360docimg_542_             *         return this.m_currPropName;
232360docimg_543_             *     }
233360docimg_544_             * }
234360docimg_545_             * 
235360docimg_546_             */

236360docimg_547_
237360docimg_548_            // 变量名称
238360docimg_549_            const string VaribleName = "m_currPropName";
239360docimg_550_
240360docimg_551_            // m_currPropName
241360docimg_552_            CodeMemberField m_currPropName_code = null;
242360docimg_553_
243360docimg_554_            // 创建字段
244360docimg_555_            m_currPropName_code = new CodeMemberField();
245360docimg_556_            // 定义为私有成员
246360docimg_557_            m_currPropName_code.Attributes = MemberAttributes.Private;
247360docimg_558_            // 创建变量
248360docimg_559_            m_currPropName_code = new CodeMemberField(typeof(string), VaribleName);
249360docimg_560_
250360docimg_561_            // 添加成员到类
251360docimg_562_            targetClass.Members.Add(m_currPropName_code);
252360docimg_563_
253360docimg_564_            // CurrentPropName
254360docimg_565_            CodeMemberProperty currPropName_code = null;
255360docimg_566_            
256360docimg_567_            // 创建属性
257360docimg_568_            currPropName_code = new CodeMemberProperty();
258360docimg_569_            // 定义为公共属性
259360docimg_570_            currPropName_code.Attributes = MemberAttributes.Public;
260360docimg_571_            // 返回字符串类型
261360docimg_572_            currPropName_code.Type = new CodeTypeReference(typeof(string));
262360docimg_573_            // 属性名称
263360docimg_574_            currPropName_code.Name = "CurrentPropName";
264360docimg_575_            // get 返回语句
265360docimg_576_            currPropName_code.GetStatements.Add(
266360docimg_577_                new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), VaribleName)));
267360docimg_578_
268360docimg_579_            // 添加属性到类
269360docimg_580_            targetClass.Members.Add(currPropName_code);
270360docimg_581_
271360docimg_582_            return targetClass;
272360docimg_583_        }

273360docimg_584_
274360docimg_585_360docimg_586_        /// <summary>
275360docimg_587_        /// 构建 CurrentDBColName 属性
276360docimg_588_        /// </summary>
277360docimg_589_        /// <param name="targetClass">父级类</param>
278360docimg_590_        /// <returns></returns>

279360docimg_591_        private CodeTypeDeclaration MakeCurrentDBColNameProperty(CodeTypeDeclaration targetClass)
280360docimg_592_360docimg_593_        {
281360docimg_595_            if (targetClass == null)
282360docimg_596_                throw new ArgumentNullException("targetClass");
283360docimg_597_
284360docimg_598_360docimg_599_            /* 
285360docimg_600_             * 以下代码将生成
286360docimg_601_             * 
287360docimg_602_             * private string m_currDBColName;
288360docimg_603_             * 
289360docimg_604_             * public string CurrentDBColName 
290360docimg_605_             * {
291360docimg_606_             *     get
292360docimg_607_             *     {
293360docimg_608_             *         return this.m_currDBColName;
294360docimg_609_             *     }
295360docimg_610_             * }
296360docimg_611_             * 
297360docimg_612_             */

298360docimg_613_
299360docimg_614_            // 变量名称
300360docimg_615_            const string VaribleName = "m_currDBColName";
301360docimg_616_            // m_currDBColName
302360docimg_617_            CodeMemberField m_currDBColName_code = null;
303360docimg_618_
304360docimg_619_            // 创建字段
305360docimg_620_            m_currDBColName_code = new CodeMemberField();
306360docimg_621_            // 定义为私有成员
307360docimg_622_            m_currDBColName_code.Attributes = MemberAttributes.Private;
308360docimg_623_            // 创建变量
309360docimg_624_            m_currDBColName_code = new CodeMemberField(typeof(string), VaribleName);
310360docimg_625_
311360docimg_626_            // 添加成员到类
312360docimg_627_            targetClass.Members.Add(m_currDBColName_code);
313360docimg_628_
314360docimg_629_            // CurrentDBColName
315360docimg_630_            CodeMemberProperty currDBCol_code = null;
316360docimg_631_
317360docimg_632_            // 创建属性
318360docimg_633_            currDBCol_code = new CodeMemberProperty();
319360docimg_634_            // 定义为公共属性
320360docimg_635_            currDBCol_code.Attributes = MemberAttributes.Public;
321360docimg_636_            // 返回字符串类型
322360docimg_637_            currDBCol_code.Type = new CodeTypeReference(typeof(string));
323360docimg_638_            // 属性名称
324360docimg_639_            currDBCol_code.Name = "CurrentDBColName";
325360docimg_640_            // get 返回语句
326360docimg_641_            currDBCol_code.GetStatements.Add(
327360docimg_642_                new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "m_currDBColName")));
328360docimg_643_
329360docimg_644_            // 添加属性到类
330360docimg_645_            targetClass.Members.Add(currDBCol_code);
331360docimg_646_
332360docimg_647_            return targetClass;
333360docimg_648_        }

334360docimg_649_
335360docimg_650_360docimg_651_        /// <summary>
336360docimg_652_        /// 构建 PutEntityProperties 方法
337360docimg_653_        /// </summary>
338360docimg_654_        /// <typeparam name="T"></typeparam>
339360docimg_655_        /// <param name="fromEntity"></param>
340360docimg_656_        /// <returns></returns>

341360docimg_657_        private CodeMemberMethod MakeMethod<T>() where T : class
342360docimg_658_360docimg_659_        {
343360docimg_661_            // PutObjectProperties 方法
344360docimg_662_            CodeMemberMethod method_code = null;
345360docimg_663_            
346360docimg_664_            // 创建方法
347360docimg_665_            method_code = new CodeMemberMethod();
348360docimg_666_            // 定义为公共方法
349360docimg_667_            method_code.Attributes = MemberAttributes.Public;
350360docimg_668_            // 返回类型
351360docimg_669_            method_code.ReturnType = new CodeTypeReference(typeof(void));
352360docimg_670_            // 方法名称
353360docimg_671_            method_code.Name = "PutEntityProperties";
354360docimg_672_            // 添加参数 entity
355360docimg_673_            method_code.Parameters.Add(new CodeParameterDeclarationExpression(typeof(T), "entity"));
356360docimg_674_            // 添加参数 dr
357360docimg_675_            method_code.Parameters.Add(new CodeParameterDeclarationExpression(typeof(DbDataReader), "dr"));
358360docimg_676_
359360docimg_677_            // 获取实体类型
360360docimg_678_            Type objType = typeof(T);
361360docimg_679_
362360docimg_680_            // 获取 DataTable 属性标记
363360docimg_681_            object[] tabAttrList = objType.GetCustomAttributes(typeof(DataTableAttribute), false);
364360docimg_682_
365360docimg_683_            if (tabAttrList == null || tabAttrList.Length <= 0)
366360docimg_684_360docimg_685_            {
367360docimg_687_                throw new MappingException(
368360docimg_688_                    String.Format(@"类 {0} 未标记 DataTable 属性 ( Unlabeled [DataTable] Attribute On Class {0} )", objType.Name));
369360docimg_689_            }

370360docimg_690_
371360docimg_691_            // 获取属性信息
372360docimg_692_            PropertyInfo[] propInfoList = objType.GetProperties();
373360docimg_693_
374360docimg_694_            if (propInfoList == null || propInfoList.Length <= 0)
375360docimg_695_                return null;
376360docimg_696_
377360docimg_697_            foreach (PropertyInfo propInfo in propInfoList)
378360docimg_698_360docimg_699_            {
379360docimg_701_                object[] colAttrList = propInfo.GetCustomAttributes(typeof(DataColumnAttribute), false);
380360docimg_702_
381360docimg_703_                // 未标记 DataColumn 属性
382360docimg_704_                if (colAttrList == null || colAttrList.Length <= 0)
383360docimg_705_                    continue;
384360docimg_706_
385360docimg_707_                // 获取数据列属性
386360docimg_708_                DataColumnAttribute colAttr = colAttrList[0as DataColumnAttribute;
387360docimg_709_
388360docimg_710_                // 创建方法内容
389360docimg_711_                method_code = this.MakeMethodContent(method_code, propInfo, colAttr, this.IncludeDebugInformation);
390360docimg_712_            }

391360docimg_713_
392360docimg_714_            return method_code;
393360docimg_715_        }

394360docimg_716_
395360docimg_717_360docimg_718_        /// <summary>
396360docimg_719_        /// 构建 PutEntityProperties 方法内容
397360docimg_720_        /// </summary>
398360docimg_721_        /// <param name="targetMethod"></param>
399360docimg_722_        /// <param name="prop"></param>
400360docimg_723_        /// <param name="attr"></param>
401360docimg_724_        /// <param name="includeDebugInfo"></param>
402360docimg_725_        /// <returns></returns>

403360docimg_726_        private CodeMemberMethod MakeMethodContent(CodeMemberMethod targetMethod, PropertyInfo prop, DataColumnAttribute attr, bool includeDebugInfo)
404360docimg_727_360docimg_728_        {
405360docimg_730_            if (targetMethod == null)
406360docimg_731_                throw new ArgumentNullException("targetMethod");
407360docimg_732_
408360docimg_733_            if (attr == null)
409360docimg_734_                throw new ArgumentNullException("attr");
410360docimg_735_
411360docimg_736_            // 实体变量名称 entity
412360docimg_737_            string varEntityName = targetMethod.Parameters[0].Name;
413360docimg_738_            // 数据源变量名称 dr
414360docimg_739_            string varDrName = targetMethod.Parameters[1].Name;
415360docimg_740_
416360docimg_741_            // entity 属性名称
417360docimg_742_            string varEntityPropName = String.Format(@"{0}.{1}", varEntityName, prop.Name);
418360docimg_743_            // dr 属性名称
419360docimg_744_            string varDrPropName = String.Format(@"{0}[""{1}""]", varDrName, attr.Name);
420360docimg_745_
421360docimg_746_            // 创建变量
422360docimg_747_            CodeVariableReferenceExpression entityProp_code = new CodeVariableReferenceExpression(varEntityPropName);
423360docimg_748_            // 创建值
424360docimg_749_            CodeVariableReferenceExpression dr_code = new CodeVariableReferenceExpression(varDrPropName);
425360docimg_750_
426360docimg_751_            // 包含调试信息
427360docimg_752_            if (includeDebugInfo)
428360docimg_753_360docimg_754_            {
429360docimg_756_                // this.m_currPropName = entity.Prop
430360docimg_757_                targetMethod.Statements.Add(new CodeAssignStatement(
431360docimg_758_                    new CodeVariableReferenceExpression("this.m_currPropName"),
432360docimg_759_                    new CodePrimitiveExpression(prop.Name)));
433360docimg_760_
434360docimg_761_                // this.m_currDBColName = attributeName
435360docimg_762_                targetMethod.Statements.Add(new CodeAssignStatement(
436360docimg_763_                    new CodeVariableReferenceExpression("this.m_currDBColName"),
437360docimg_764_                    new CodePrimitiveExpression(attr.Name)));
438360docimg_765_            }

439360docimg_766_
440360docimg_767_            if (attr.IsNullable)
441360docimg_768_360docimg_769_            {
442360docimg_771_360docimg_772_                /* 
443360docimg_773_                 * 以下代码生成的是条件判断代码
444360docimg_774_                 * 
445360docimg_775_                 * if (dr["360docimg_776_"] != DBNull.Value) {
446360docimg_777_                 *     entity.Prop = dr["360docimg_778_"];
447360docimg_779_                 * }
448360docimg_780_                 * 
449360docimg_781_                 */

450360docimg_782_
451360docimg_783_                CodeConditionStatement if_code = new CodeConditionStatement();
452360docimg_784_
453360docimg_785_                // if (dr["360docimg_786_"] != DBNull.Value)
454360docimg_787_                if_code.Condition = new CodeBinaryOperatorExpression(
455360docimg_788_                    new CodeVariableReferenceExpression(varDrPropName),
456360docimg_789_                    CodeBinaryOperatorType.IdentityInequality,
457360docimg_790_                    new CodeVariableReferenceExpression("System.DBNull.Value"));
458360docimg_791_
459360docimg_792_                // entity.Prop = dr["360docimg_793_"];
460360docimg_794_                if_code.TrueStatements.Add(new CodeAssignStatement(
461360docimg_795_                    entityProp_code,
462360docimg_796_                    new CodeCastExpression(prop.PropertyType, dr_code)));
463360docimg_797_
464360docimg_798_                targetMethod.Statements.Add(if_code);
465360docimg_799_            }

466360docimg_800_            else
467360docimg_801_360docimg_802_            {
468360docimg_804_                // entity.Prop = dr["360docimg_805_"];
469360docimg_806_                targetMethod.Statements.Add(new CodeAssignStatement(
470360docimg_807_                    entityProp_code,
471360docimg_808_                    new CodeCastExpression(prop.PropertyType, dr_code)));
472360docimg_809_            }

473360docimg_810_
474360docimg_811_            return targetMethod;
475360docimg_812_        }

476360docimg_813_    }

477360docimg_814_}

代码时序图如下:

 
360docimg_815_

具体代码可以参考:
Net.AfritXia.Data/IEntityPropertyPutter.cs
Net.AfritXia.Data/EntityPropertyPutterFactory.cs
Net.AfritXia.Data/EntityPropertyPutterMaker.cs
TestProj/UnitTest_Putter.cs(可以运行该测试文件)

posted on 2008-07-06 13:53 AfritXia 阅读(1269) 评论(10)  编辑 收藏

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
通用的高度可扩展的Excel导入实现(附Demo)
CodeDOM浅析(下)
spring 的Column注解
Spring+JPA 通用DAO及实现
Entity Framework 实体框架的形成之旅--Code First的框架设计(5)
JPA关系映射
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服