使用CodeDom提高ORM性能

下载本文代码:http://files.cnblogs.com/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 None.gif      public   class  LWordEntity
 2 ExpandedBlockStart.gifContractedBlock.gif     dot.gif {
 3ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
 4InBlock.gif        /// 获取或设置留言 ID
 5ExpandedSubBlockEnd.gif        /// </summary>

 6InBlock.gif        [DataColumn(ColumnName = "LWordUID")]
 7InBlock.gif        public int LWordUID
 8ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 9InBlock.gif            // dot.gif
10ExpandedSubBlockEnd.gif        }

11InBlock.gif
12ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
13InBlock.gif        /// 获取或设置发送用户
14ExpandedSubBlockEnd.gif        /// </summary>

15InBlock.gif        [DataColumn(ColumnName = "PostUser")]
16InBlock.gif        public string PostUser
17ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
18InBlock.gif            // dot.gif
19ExpandedSubBlockEnd.gif        }

20InBlock.gif
21ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
22InBlock.gif        /// 获取或设置发送时间
23ExpandedSubBlockEnd.gif        /// </summary>

24InBlock.gif        [DataColumn(ColumnName = "PostTime")]
25InBlock.gif        public DateTime PostTime
26ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
27InBlock.gif            // dot.gif
28ExpandedSubBlockEnd.gif        }

29InBlock.gif
30ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
31InBlock.gif        /// 获取或设置文本内容
32ExpandedSubBlockEnd.gif        /// </summary>

33InBlock.gif        [DataColumn(ColumnName = "TextContent")]
34InBlock.gif        public string TextContent
35ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
36InBlock.gif            // dot.gif
37ExpandedSubBlockEnd.gif        }

38ExpandedBlockEnd.gif    }


  DataColumn是自定义的属性类,代码并不复杂所以在这里也就省略了。接下来需要通过反射读取自定义属性,并赋值。代码如下:


 1 None.gif      public   void  PutEntityProperties( object  objEntity, DbDataReader dr)
 2 ExpandedBlockStart.gifContractedBlock.gif     dot.gif {
 3InBlock.gif        // 获取实体类型
 4InBlock.gif        Type objType = objEntity.GetType();
 5InBlock.gif
 6InBlock.gif        // 获取属性信息
 7InBlock.gif        PropertyInfo[] propInfoList = objType.GetProperties();
 8InBlock.gif
 9InBlock.gif        if (propInfoList == null || propInfoList.Length <= 0)
10InBlock.gif            return;
11InBlock.gif
12InBlock.gif        foreach (PropertyInfo propInfo in propInfoList)
13ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
14InBlock.gif            object[] colAttrList = propInfo.GetCustomAttributes(typeof(DataColumnAttribute), false);
15InBlock.gif
16InBlock.gif            // 未标记 DataColumn 属性
17InBlock.gif            if (colAttrList == null || colAttrList.Length <= 0)
18InBlock.gif                continue;
19InBlock.gif
20InBlock.gif            // 获取数据列属性
21InBlock.gif            DataColumnAttribute colAttr = colAttrList[0as DataColumnAttribute;
22InBlock.gif
23InBlock.gif            int ordinal = -1;
24InBlock.gif
25InBlock.gif            try
26ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
27InBlock.gif                // 获取数据列序号
28InBlock.gif                ordinal = dr.GetOrdinal(colAttr.ColumnName);
29ExpandedSubBlockEnd.gif            }

30InBlock.gif            catch (Exception ex)
31ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
32InBlock.gif                throw new MappingException(
33InBlock.gif                    String.Format("{0} 未找到该数据列( Cannot Found this Column {0} )", colAttr.ColumnName), ex);
34ExpandedSubBlockEnd.gif            }

35InBlock.gif
36InBlock.gif            // 获取数据列值
37InBlock.gif            object objValue = dr.GetValue(ordinal);
38InBlock.gif
39InBlock.gif            if (objValue is DBNull)
40ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
41InBlock.gif                // 将 null 值设置到属性
42InBlock.gif                propInfo.SetValue(objEntity, nullnull);
43ExpandedSubBlockEnd.gif            }

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

49ExpandedSubBlockEnd.gif        }

50ExpandedBlockEnd.gif    }

51 None.gif


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

 1 None.gif          void  PutEntityProperties(NewsEntity entity, DbDataReader dr)
 2 ExpandedBlockStart.gifContractedBlock.gif         dot.gif {
 3InBlock.gif            // 新闻 ID
 4InBlock.gif            entity.ID = (int)dr["ID"];
 5InBlock.gif            // 标题
 6InBlock.gif            entity.Title = (string)dr["Title"];
 7InBlock.gif            // 摘要
 8InBlock.gif            entity.Summary = (string)dr["Summary"];
 9InBlock.gif            // 发送用户
10InBlock.gif            entity.PostUser = (string)dr["PostUser"];
11InBlock.gif            // 发送时间
12InBlock.gif            entity.PostTime = (DateTime)dr["PostTime"];
13InBlock.gif            // 文本内容
14InBlock.gif            entity.TextContent = (string)dr["TextContent"];
15ExpandedBlockEnd.gif        }

 

User实体赋值代码:

 1 None.gif          void  PutEntityProperties(UserEntity entity, DbDataReader dr)
 2 ExpandedBlockStart.gifContractedBlock.gif         dot.gif {
 3InBlock.gif            // 用户 ID
 4InBlock.gif            entity.ID = (int)dr["ID"];
 5InBlock.gif            // 用户名称
 6InBlock.gif            entity.UserName = (string)dr["UserName"];
 7InBlock.gif            // 密码
 8InBlock.gif            entity.UserPass = (string)dr["UserPass"];
 9InBlock.gif            // 电子邮件
10InBlock.gif            entity.EMail = (string)dr["EMail"];
11InBlock.gif            // 注册时间
12InBlock.gif            entity.RegisterTime = (DateTime)dr["RegisterTime"];
13ExpandedBlockEnd.gif        }

14 None.gif


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


WebTest.jpg


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

 
Class_Diagram__Class__SQLHelper.jpg

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

 1 None.gif using  System;
 2 None.gif using  System.Collections.Generic;
 3 None.gif using  System.Data.Common;
 4 None.gif using  System.Reflection;
 5 None.gif
 6 None.gif using  Net.AfritXia.Data.Mapping;
 7 None.gif
 8 None.gif namespace  Net.AfritXia.Data
 9 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
10InBlock.gif    partial class SQLHelper
11ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
12InBlock.gif        public void PutEntityProperties<T>(T entity, DbDataReader dr) where T : class
13ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
14InBlock.gif            // 获取设置器
15InBlock.gif            IEntityPropertyPutter<T> putter = EntityPropertyPutterFactory.Create<T>(entity, this.IncludeDebugInformation);
16InBlock.gif
17InBlock.gif            if (putter == null)
18InBlock.gif                throw new NullReferenceException(@"设置器为空( Null Putter )");
19InBlock.gif
20InBlock.gif            try
21ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
22InBlock.gif                // 设置实体属性
23InBlock.gif                putter.PutEntityProperties(entity, dr);
24ExpandedSubBlockEnd.gif            }

25InBlock.gif            catch (Exception ex)
26ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
27InBlock.gif                string errorMessage = null;
28InBlock.gif                
29InBlock.gif                // 定义异常信息格式
30InBlock.gif                errorMessage = @"从数据库字段{0} 读取值并赋给属性{1} 时出错(实体类型: {2})";
31InBlock.gif                // 格式化信息
32InBlock.gif                errorMessage = String.Format(errorMessage, putter.CurrentDBColName, putter.CurrentPropName, putter.EntityTypeName);
33InBlock.gif
34InBlock.gif                // 抛出异常
35InBlock.gif                throw new Exception(errorMessage, ex);
36ExpandedSubBlockEnd.gif            }

37ExpandedSubBlockEnd.gif        }

38ExpandedSubBlockEnd.gif    }

39ExpandedBlockEnd.gif}

40 None.gif

 

设置器工厂类EntityPropertyPutterFactory:

 

 1 None.gif using  System;
 2 None.gif using  System.Collections;
 3 None.gif using  System.Reflection;
 4 None.gif
 5 None.gif namespace  Net.AfritXia.Data
 6 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
 7ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
 8InBlock.gif    /// 实体属性设置器工厂类
 9ExpandedSubBlockEnd.gif    /// </summary>

10InBlock.gif    internal sealed class EntityPropertyPutterFactory
11ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
12InBlock.gif        // 设置器字典
13InBlock.gif        private static readonly Hashtable g_putterHash = Hashtable.Synchronized(new Hashtable());
14InBlock.gif
15ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
16InBlock.gif        /// 创建实体属性设置器
17InBlock.gif        /// </summary>
18InBlock.gif        /// <typeparam name="T">实体类型模版</typeparam>
19InBlock.gif        /// <param name="fromEntity">实体</param>
20InBlock.gif        /// <param name="includeDebugInfo">是否包含调试信息</param>
21ExpandedSubBlockEnd.gif        /// <returns></returns>

22InBlock.gif        public static IEntityPropertyPutter<T> Create<T>(T fromEntity, bool includeDebugInfo) where T : class
23ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
24InBlock.gif            if (fromEntity == null)
25InBlock.gif                return null;
26InBlock.gif
27InBlock.gif            // 如果实体本身已经实现了 IEntityPropertyPutter<T> 接口, 
28InBlock.gif            // 则直接返回
29InBlock.gif            if (fromEntity is IEntityPropertyPutter<T>)
30InBlock.gif                return (IEntityPropertyPutter<T>)fromEntity;
31InBlock.gif
32InBlock.gif            IEntityPropertyPutter<T> putter = null;
33InBlock.gif
34InBlock.gif            // 获取字典关键字
35InBlock.gif            string hashKey = fromEntity.GetType().FullName;
36InBlock.gif
37InBlock.gif            if (g_putterHash.ContainsKey(hashKey))
38ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
39InBlock.gif                // 从字典中获取设置器
40InBlock.gif                putter = g_putterHash[hashKey] as IEntityPropertyPutter<T>;
41ExpandedSubBlockEnd.gif            }

42InBlock.gif            else
43ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
44InBlock.gif                EntityPropertyPutterMaker maker = null;
45InBlock.gif
46InBlock.gif                // 创建构建器
47InBlock.gif                maker = new EntityPropertyPutterMaker();
48InBlock.gif                // 是否包含调试信息
49InBlock.gif                maker.IncludeDebugInformation = includeDebugInfo;
50InBlock.gif
51InBlock.gif                // 新建应用程序集
52InBlock.gif                putter = maker.Make<T>();
53InBlock.gif                // 保存应用设置器到字典
54InBlock.gif                g_putterHash.Add(hashKey, putter);
55ExpandedSubBlockEnd.gif            }

56InBlock.gif
57InBlock.gif            return putter;
58ExpandedSubBlockEnd.gif        }

59ExpandedSubBlockEnd.gif    }

60ExpandedBlockEnd.gif}

构建器EntityPropertyPutterMaker:

  1 None.gif #undef  _Debug   //  用于调试
  2 None.gif
  3 None.gif using  System;
  4 None.gif using  System.CodeDom;
  5 None.gif using  System.Collections.Specialized;
  6 None.gif using  System.CodeDom.Compiler;
  7 None.gif using  System.Data.Common;
  8 None.gif #if  _Debug
  9 None.gif using  System.IO;
 10 None.gif #endif
 11 None.gif using  System.Reflection;
 12 None.gif
 13 None.gif using  Microsoft.CSharp;
 14 None.gif
 15 None.gif using  Net.AfritXia.Data.Mapping;
 16 None.gif
 17 None.gif namespace  Net.AfritXia.Data
 18 ExpandedBlockStart.gifContractedBlock.gif dot.gif {
 19ExpandedSubBlockStart.gifContractedSubBlock.gif    /**//// <summary>
 20InBlock.gif    /// 构建实体属性设置器
 21ExpandedSubBlockEnd.gif    /// </summary>

 22InBlock.gif    internal sealed class EntityPropertyPutterMaker
 23ExpandedSubBlockStart.gifContractedSubBlock.gif    dot.gif{
 24InBlock.gif        // 默认名称空间
 25InBlock.gif        private const string DefaultNamespace = "Net.AfritXia.Data._AutoCode";
 26InBlock.gif        // QuicklyPutter 类名称
 27InBlock.gif        private const string QuicklyPutterClassName = "QuicklyPutter";
 28InBlock.gif
 29InBlock.gif        // 包含调试信息
 30InBlock.gif        private bool m_includeDebugInfo = false;
 31InBlock.gif
 32ContractedSubBlock.gifExpandedSubBlockStart.gif        类构造器#region 类构造器
 33ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
 34InBlock.gif        /// 类默认构造器
 35ExpandedSubBlockEnd.gif        /// </summary>

 36InBlock.gif        public EntityPropertyPutterMaker()
 37ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 38ExpandedSubBlockEnd.gif        }

 39ExpandedSubBlockEnd.gif        #endregion

 40InBlock.gif
 41ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
 42InBlock.gif        /// 设置或获取是否包含调试信息
 43ExpandedSubBlockEnd.gif        /// </summary>

 44InBlock.gif        public bool IncludeDebugInformation
 45ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 46InBlock.gif            set
 47ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 48InBlock.gif                this.m_includeDebugInfo = value;
 49ExpandedSubBlockEnd.gif            }

 50InBlock.gif
 51InBlock.gif            get
 52ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
 53InBlock.gif                return this.m_includeDebugInfo;
 54ExpandedSubBlockEnd.gif            }

 55ExpandedSubBlockEnd.gif        }

 56InBlock.gif
 57ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
 58InBlock.gif        /// 构建实体属性设置器
 59InBlock.gif        /// </summary>
 60InBlock.gif        /// <typeparam name="T">实体类型模版</typeparam>
 61ExpandedSubBlockEnd.gif        /// <returns></returns>

 62InBlock.gif        public IEntityPropertyPutter<T> Make<T>() where T : class
 63ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
 64InBlock.gif            // 创建一个可编译的单元
 65InBlock.gif            CodeCompileUnit compileUnit = this.MakeCompileUnit();
 66InBlock.gif            // 创建名称空间
 67InBlock.gif            CodeNamespace namespace_code = this.MakeNamespace();
 68InBlock.gif            // 定义类
 69InBlock.gif            CodeTypeDeclaration class_code = this.MakeClass<T>();
 70InBlock.gif            // 创建 PutEntityProperties 方法
 71InBlock.gif            CodeMemberMethod method_code = this.MakeMethod<T>();
 72InBlock.gif
 73InBlock.gif            // 添加方法到类
 74InBlock.gif            class_code.Members.Add(method_code);
 75InBlock.gif            // 添加类到名称空间
 76InBlock.gif            namespace_code.Types.Add(class_code);
 77InBlock.gif            // 添加名称空间到编译单元
 78InBlock.gif            compileUnit.Namespaces.Add(namespace_code);
 79InBlock.gif
 80InBlock.gif            // 创建 C# 编译器
 81InBlock.gif            CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
 82InBlock.gif            // 创建编译参数
 83InBlock.gif            CompilerParameters options = new CompilerParameters();
 84InBlock.gif
 85InBlock.gif            // 添加对 System.dll 的引用
 86InBlock.gif            options.ReferencedAssemblies.Add("System.dll");
 87InBlock.gif            // 添加对 System.Data.dll 的引用
 88InBlock.gif            options.ReferencedAssemblies.Add("System.Data.dll");
 89InBlock.gif            // 添加对该项目的引用
 90InBlock.gif            options.ReferencedAssemblies.Add(this.GetType().Assembly.Location);
 91InBlock.gif            // 添加对实体项目的引用
 92InBlock.gif            options.ReferencedAssemblies.Add(typeof(T).Assembly.Location);
 93InBlock.gif            // 只在内存中编译
 94InBlock.gif            options.GenerateInMemory = true;
 95InBlock.gif
 96InBlock.gif#if _Debug
 97InBlock.gif            string srcFilePath = null;
 98InBlock.gif
 99InBlock.gif            srcFilePath = @"C:\{0}_{1}.cs";
100InBlock.gif            srcFilePath = String.Format(srcFilePath, typeof(T).Name, QuicklyPutterClassName);
101InBlock.gif
102InBlock.gif            // 源文件输出流
103InBlock.gif            StreamWriter srcOutput = new StreamWriter(srcFilePath, false);
104InBlock.gif            // 写出源文件
105InBlock.gif            provider.GenerateCodeFromCompileUnit(compileUnit, srcOutput, new CodeGeneratorOptions());
106InBlock.gif
107InBlock.gif            srcOutput.Flush();
108InBlock.gif            srcOutput.Close();
109InBlock.gif#endif
110InBlock.gif
111InBlock.gif            // 编译并获取编译结果
112InBlock.gif            CompilerResults compileResult = provider.CompileAssemblyFromDom(options, compileUnit);
113InBlock.gif
114InBlock.gif            // 编译失败则抛出异常
115InBlock.gif            if (compileResult.NativeCompilerReturnValue != 0)
116InBlock.gif                throw new Exception("编译失败 ( Compile Failed )");
117InBlock.gif
118InBlock.gif            // 创建设置器
119InBlock.gif            object putter = compileResult.CompiledAssembly.CreateInstance(DefaultNamespace + "." + QuicklyPutterClassName);
120InBlock.gif
121InBlock.gif            return (IEntityPropertyPutter<T>)putter;
122ExpandedSubBlockEnd.gif        }

123InBlock.gif
124ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
125InBlock.gif        /// 构建可编译单元
126InBlock.gif        /// </summary>
127ExpandedSubBlockEnd.gif        /// <returns></returns>

128InBlock.gif        private CodeCompileUnit MakeCompileUnit()
129ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
130InBlock.gif            // 创建一个可编译的单元
131InBlock.gif            return new CodeCompileUnit();
132ExpandedSubBlockEnd.gif        }

133InBlock.gif
134ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
135InBlock.gif        /// 构建名称空间
136InBlock.gif        /// </summary>
137ExpandedSubBlockEnd.gif        /// <returns></returns>

138InBlock.gif        private CodeNamespace MakeNamespace()
139ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
140InBlock.gif            // 创建名称空间
141InBlock.gif            return new CodeNamespace(DefaultNamespace);
142ExpandedSubBlockEnd.gif        }

143InBlock.gif
144ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
145InBlock.gif        /// 构建 QuicklyPutter 类
146InBlock.gif        /// </summary>
147ExpandedSubBlockEnd.gif        /// <returns></returns>

148InBlock.gif        private CodeTypeDeclaration MakeClass<T>() where T : class
149ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
150InBlock.gif            // 定义 QuicklyPutter 类
151InBlock.gif            CodeTypeDeclaration class_code = new CodeTypeDeclaration(QuicklyPutterClassName);
152InBlock.gif
153InBlock.gif            // 令该类实现 IEntityPropertyPutter<T> 接口
154InBlock.gif            class_code.BaseTypes.Add(typeof(IEntityPropertyPutter<T>));
155InBlock.gif
156InBlock.gif            // 添加 EntityTypeName 属性
157InBlock.gif            class_code = this.MakeEntityTypeNameProperty<T>(class_code);
158InBlock.gif            // 添加 CurrentPropName 属性
159InBlock.gif            class_code = this.MakeCurrentPropNameProperty(class_code);
160InBlock.gif            // 添加 CurrentDBColName 属性
161InBlock.gif            class_code = this.MakeCurrentDBColNameProperty(class_code);
162InBlock.gif
163InBlock.gif            return class_code;
164ExpandedSubBlockEnd.gif        }

165InBlock.gif
166ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
167InBlock.gif        /// 构建 EntityTypeName 属性
168InBlock.gif        /// </summary>
169InBlock.gif        /// <typeparam name="T">实体类型模版</typeparam>
170InBlock.gif        /// <param name="targetClass">目标代码</param>
171ExpandedSubBlockEnd.gif        /// <returns></returns>

172InBlock.gif        private CodeTypeDeclaration MakeEntityTypeNameProperty<T>(CodeTypeDeclaration targetClass) where T : class
173ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
174InBlock.gif            if (targetClass == null)
175InBlock.gif                throw new ArgumentNullException("targetClass");
176InBlock.gif
177ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//* 
178InBlock.gif             * 以下代码将生成
179InBlock.gif             * 
180InBlock.gif             * public string EntityTypeName
181InBlock.gif             * {
182InBlock.gif             *     get
183InBlock.gif             *     {
184InBlock.gif             *         return 实体类型名称字符串
185InBlock.gif             *     }
186InBlock.gif             * }
187InBlock.gif             * 
188InBlock.gif             * 
189ExpandedSubBlockEnd.gif             */

190InBlock.gif
191InBlock.gif            // EntityTypeName 属性
192InBlock.gif            CodeMemberProperty entityTypeNameProp_code = null;
193InBlock.gif            
194InBlock.gif            // 创建属性
195InBlock.gif            entityTypeNameProp_code = new CodeMemberProperty();
196InBlock.gif            // 定义为公共属性
197InBlock.gif            entityTypeNameProp_code.Attributes = MemberAttributes.Public;
198InBlock.gif            // 返回字符串类型
199InBlock.gif            entityTypeNameProp_code.Type = new CodeTypeReference(typeof(string));
200InBlock.gif            // 属性名称
201InBlock.gif            entityTypeNameProp_code.Name = "EntityTypeName";
202InBlock.gif            // 返回语句
203InBlock.gif            entityTypeNameProp_code.GetStatements.Add(
204InBlock.gif                new CodeMethodReturnStatement(new CodePrimitiveExpression(typeof(T).Name)));
205InBlock.gif
206InBlock.gif            // 添加属性到类
207InBlock.gif            targetClass.Members.Add(entityTypeNameProp_code);
208InBlock.gif
209InBlock.gif            return targetClass;
210ExpandedSubBlockEnd.gif        }

211InBlock.gif
212ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
213InBlock.gif        /// 构建 CurrentPropName 属性
214InBlock.gif        /// </summary>
215InBlock.gif        /// <param name="targetClass">目标类代码</param>
216ExpandedSubBlockEnd.gif        /// <returns></returns>

217InBlock.gif        private CodeTypeDeclaration MakeCurrentPropNameProperty(CodeTypeDeclaration targetClass)
218ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
219InBlock.gif            if (targetClass == null)
220InBlock.gif                throw new ArgumentNullException("targetClass");
221InBlock.gif
222ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//* 
223InBlock.gif             * 以下代码将生成
224InBlock.gif             * 
225InBlock.gif             * private string m_currPropName;
226InBlock.gif             * 
227InBlock.gif             * public string CurrentPropName 
228InBlock.gif             * {
229InBlock.gif             *     get
230InBlock.gif             *     {
231InBlock.gif             *         return this.m_currPropName;
232InBlock.gif             *     }
233InBlock.gif             * }
234InBlock.gif             * 
235ExpandedSubBlockEnd.gif             */

236InBlock.gif
237InBlock.gif            // 变量名称
238InBlock.gif            const string VaribleName = "m_currPropName";
239InBlock.gif
240InBlock.gif            // m_currPropName
241InBlock.gif            CodeMemberField m_currPropName_code = null;
242InBlock.gif
243InBlock.gif            // 创建字段
244InBlock.gif            m_currPropName_code = new CodeMemberField();
245InBlock.gif            // 定义为私有成员
246InBlock.gif            m_currPropName_code.Attributes = MemberAttributes.Private;
247InBlock.gif            // 创建变量
248InBlock.gif            m_currPropName_code = new CodeMemberField(typeof(string), VaribleName);
249InBlock.gif
250InBlock.gif            // 添加成员到类
251InBlock.gif            targetClass.Members.Add(m_currPropName_code);
252InBlock.gif
253InBlock.gif            // CurrentPropName
254InBlock.gif            CodeMemberProperty currPropName_code = null;
255InBlock.gif            
256InBlock.gif            // 创建属性
257InBlock.gif            currPropName_code = new CodeMemberProperty();
258InBlock.gif            // 定义为公共属性
259InBlock.gif            currPropName_code.Attributes = MemberAttributes.Public;
260InBlock.gif            // 返回字符串类型
261InBlock.gif            currPropName_code.Type = new CodeTypeReference(typeof(string));
262InBlock.gif            // 属性名称
263InBlock.gif            currPropName_code.Name = "CurrentPropName";
264InBlock.gif            // get 返回语句
265InBlock.gif            currPropName_code.GetStatements.Add(
266InBlock.gif                new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), VaribleName)));
267InBlock.gif
268InBlock.gif            // 添加属性到类
269InBlock.gif            targetClass.Members.Add(currPropName_code);
270InBlock.gif
271InBlock.gif            return targetClass;
272ExpandedSubBlockEnd.gif        }

273InBlock.gif
274ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
275InBlock.gif        /// 构建 CurrentDBColName 属性
276InBlock.gif        /// </summary>
277InBlock.gif        /// <param name="targetClass">父级类</param>
278ExpandedSubBlockEnd.gif        /// <returns></returns>

279InBlock.gif        private CodeTypeDeclaration MakeCurrentDBColNameProperty(CodeTypeDeclaration targetClass)
280ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
281InBlock.gif            if (targetClass == null)
282InBlock.gif                throw new ArgumentNullException("targetClass");
283InBlock.gif
284ExpandedSubBlockStart.gifContractedSubBlock.gif            /**//* 
285InBlock.gif             * 以下代码将生成
286InBlock.gif             * 
287InBlock.gif             * private string m_currDBColName;
288InBlock.gif             * 
289InBlock.gif             * public string CurrentDBColName 
290InBlock.gif             * {
291InBlock.gif             *     get
292InBlock.gif             *     {
293InBlock.gif             *         return this.m_currDBColName;
294InBlock.gif             *     }
295InBlock.gif             * }
296InBlock.gif             * 
297ExpandedSubBlockEnd.gif             */

298InBlock.gif
299InBlock.gif            // 变量名称
300InBlock.gif            const string VaribleName = "m_currDBColName";
301InBlock.gif            // m_currDBColName
302InBlock.gif            CodeMemberField m_currDBColName_code = null;
303InBlock.gif
304InBlock.gif            // 创建字段
305InBlock.gif            m_currDBColName_code = new CodeMemberField();
306InBlock.gif            // 定义为私有成员
307InBlock.gif            m_currDBColName_code.Attributes = MemberAttributes.Private;
308InBlock.gif            // 创建变量
309InBlock.gif            m_currDBColName_code = new CodeMemberField(typeof(string), VaribleName);
310InBlock.gif
311InBlock.gif            // 添加成员到类
312InBlock.gif            targetClass.Members.Add(m_currDBColName_code);
313InBlock.gif
314InBlock.gif            // CurrentDBColName
315InBlock.gif            CodeMemberProperty currDBCol_code = null;
316InBlock.gif
317InBlock.gif            // 创建属性
318InBlock.gif            currDBCol_code = new CodeMemberProperty();
319InBlock.gif            // 定义为公共属性
320InBlock.gif            currDBCol_code.Attributes = MemberAttributes.Public;
321InBlock.gif            // 返回字符串类型
322InBlock.gif            currDBCol_code.Type = new CodeTypeReference(typeof(string));
323InBlock.gif            // 属性名称
324InBlock.gif            currDBCol_code.Name = "CurrentDBColName";
325InBlock.gif            // get 返回语句
326InBlock.gif            currDBCol_code.GetStatements.Add(
327InBlock.gif                new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "m_currDBColName")));
328InBlock.gif
329InBlock.gif            // 添加属性到类
330InBlock.gif            targetClass.Members.Add(currDBCol_code);
331InBlock.gif
332InBlock.gif            return targetClass;
333ExpandedSubBlockEnd.gif        }

334InBlock.gif
335ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
336InBlock.gif        /// 构建 PutEntityProperties 方法
337InBlock.gif        /// </summary>
338InBlock.gif        /// <typeparam name="T"></typeparam>
339InBlock.gif        /// <param name="fromEntity"></param>
340ExpandedSubBlockEnd.gif        /// <returns></returns>

341InBlock.gif        private CodeMemberMethod MakeMethod<T>() where T : class
342ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
343InBlock.gif            // PutObjectProperties 方法
344InBlock.gif            CodeMemberMethod method_code = null;
345InBlock.gif            
346InBlock.gif            // 创建方法
347InBlock.gif            method_code = new CodeMemberMethod();
348InBlock.gif            // 定义为公共方法
349InBlock.gif            method_code.Attributes = MemberAttributes.Public;
350InBlock.gif            // 返回类型
351InBlock.gif            method_code.ReturnType = new CodeTypeReference(typeof(void));
352InBlock.gif            // 方法名称
353InBlock.gif            method_code.Name = "PutEntityProperties";
354InBlock.gif            // 添加参数 entity
355InBlock.gif            method_code.Parameters.Add(new CodeParameterDeclarationExpression(typeof(T), "entity"));
356InBlock.gif            // 添加参数 dr
357InBlock.gif            method_code.Parameters.Add(new CodeParameterDeclarationExpression(typeof(DbDataReader), "dr"));
358InBlock.gif
359InBlock.gif            // 获取实体类型
360InBlock.gif            Type objType = typeof(T);
361InBlock.gif
362InBlock.gif            // 获取 DataTable 属性标记
363InBlock.gif            object[] tabAttrList = objType.GetCustomAttributes(typeof(DataTableAttribute), false);
364InBlock.gif
365InBlock.gif            if (tabAttrList == null || tabAttrList.Length <= 0)
366ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
367InBlock.gif                throw new MappingException(
368InBlock.gif                    String.Format(@"类 {0} 未标记 DataTable 属性 ( Unlabeled [DataTable] Attribute On Class {0} )", objType.Name));
369ExpandedSubBlockEnd.gif            }

370InBlock.gif
371InBlock.gif            // 获取属性信息
372InBlock.gif            PropertyInfo[] propInfoList = objType.GetProperties();
373InBlock.gif
374InBlock.gif            if (propInfoList == null || propInfoList.Length <= 0)
375InBlock.gif                return null;
376InBlock.gif
377InBlock.gif            foreach (PropertyInfo propInfo in propInfoList)
378ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
379InBlock.gif                object[] colAttrList = propInfo.GetCustomAttributes(typeof(DataColumnAttribute), false);
380InBlock.gif
381InBlock.gif                // 未标记 DataColumn 属性
382InBlock.gif                if (colAttrList == null || colAttrList.Length <= 0)
383InBlock.gif                    continue;
384InBlock.gif
385InBlock.gif                // 获取数据列属性
386InBlock.gif                DataColumnAttribute colAttr = colAttrList[0as DataColumnAttribute;
387InBlock.gif
388InBlock.gif                // 创建方法内容
389InBlock.gif                method_code = this.MakeMethodContent(method_code, propInfo, colAttr, this.IncludeDebugInformation);
390ExpandedSubBlockEnd.gif            }

391InBlock.gif
392InBlock.gif            return method_code;
393ExpandedSubBlockEnd.gif        }

394InBlock.gif
395ExpandedSubBlockStart.gifContractedSubBlock.gif        /**//// <summary>
396InBlock.gif        /// 构建 PutEntityProperties 方法内容
397InBlock.gif        /// </summary>
398InBlock.gif        /// <param name="targetMethod"></param>
399InBlock.gif        /// <param name="prop"></param>
400InBlock.gif        /// <param name="attr"></param>
401InBlock.gif        /// <param name="includeDebugInfo"></param>
402ExpandedSubBlockEnd.gif        /// <returns></returns>

403InBlock.gif        private CodeMemberMethod MakeMethodContent(CodeMemberMethod targetMethod, PropertyInfo prop, DataColumnAttribute attr, bool includeDebugInfo)
404ExpandedSubBlockStart.gifContractedSubBlock.gif        dot.gif{
405InBlock.gif            if (targetMethod == null)
406InBlock.gif                throw new ArgumentNullException("targetMethod");
407InBlock.gif
408InBlock.gif            if (attr == null)
409InBlock.gif                throw new ArgumentNullException("attr");
410InBlock.gif
411InBlock.gif            // 实体变量名称 entity
412InBlock.gif            string varEntityName = targetMethod.Parameters[0].Name;
413InBlock.gif            // 数据源变量名称 dr
414InBlock.gif            string varDrName = targetMethod.Parameters[1].Name;
415InBlock.gif
416InBlock.gif            // entity 属性名称
417InBlock.gif            string varEntityPropName = String.Format(@"{0}.{1}", varEntityName, prop.Name);
418InBlock.gif            // dr 属性名称
419InBlock.gif            string varDrPropName = String.Format(@"{0}[""{1}""]", varDrName, attr.Name);
420InBlock.gif
421InBlock.gif            // 创建变量
422InBlock.gif            CodeVariableReferenceExpression entityProp_code = new CodeVariableReferenceExpression(varEntityPropName);
423InBlock.gif            // 创建值
424InBlock.gif            CodeVariableReferenceExpression dr_code = new CodeVariableReferenceExpression(varDrPropName);
425InBlock.gif
426InBlock.gif            // 包含调试信息
427InBlock.gif            if (includeDebugInfo)
428ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
429InBlock.gif                // this.m_currPropName = entity.Prop
430InBlock.gif                targetMethod.Statements.Add(new CodeAssignStatement(
431InBlock.gif                    new CodeVariableReferenceExpression("this.m_currPropName"),
432InBlock.gif                    new CodePrimitiveExpression(prop.Name)));
433InBlock.gif
434InBlock.gif                // this.m_currDBColName = attributeName
435InBlock.gif                targetMethod.Statements.Add(new CodeAssignStatement(
436InBlock.gif                    new CodeVariableReferenceExpression("this.m_currDBColName"),
437InBlock.gif                    new CodePrimitiveExpression(attr.Name)));
438ExpandedSubBlockEnd.gif            }

439InBlock.gif
440InBlock.gif            if (attr.IsNullable)
441ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
442ExpandedSubBlockStart.gifContractedSubBlock.gif                /**//* 
443InBlock.gif                 * 以下代码生成的是条件判断代码
444InBlock.gif                 * 
445InBlock.gif                 * if (dr["dot.gif"] != DBNull.Value) {
446InBlock.gif                 *     entity.Prop = dr["dot.gif"];
447InBlock.gif                 * }
448InBlock.gif                 * 
449ExpandedSubBlockEnd.gif                 */

450InBlock.gif
451InBlock.gif                CodeConditionStatement if_code = new CodeConditionStatement();
452InBlock.gif
453InBlock.gif                // if (dr["dot.gif"] != DBNull.Value)
454InBlock.gif                if_code.Condition = new CodeBinaryOperatorExpression(
455InBlock.gif                    new CodeVariableReferenceExpression(varDrPropName),
456InBlock.gif                    CodeBinaryOperatorType.IdentityInequality,
457InBlock.gif                    new CodeVariableReferenceExpression("System.DBNull.Value"));
458InBlock.gif
459InBlock.gif                // entity.Prop = dr["dot.gif"];
460InBlock.gif                if_code.TrueStatements.Add(new CodeAssignStatement(
461InBlock.gif                    entityProp_code,
462InBlock.gif                    new CodeCastExpression(prop.PropertyType, dr_code)));
463InBlock.gif
464InBlock.gif                targetMethod.Statements.Add(if_code);
465ExpandedSubBlockEnd.gif            }

466InBlock.gif            else
467ExpandedSubBlockStart.gifContractedSubBlock.gif            dot.gif{
468InBlock.gif                // entity.Prop = dr["dot.gif"];
469InBlock.gif                targetMethod.Statements.Add(new CodeAssignStatement(
470InBlock.gif                    entityProp_code,
471InBlock.gif                    new CodeCastExpression(prop.PropertyType, dr_code)));
472ExpandedSubBlockEnd.gif            }

473InBlock.gif
474InBlock.gif            return targetMethod;
475ExpandedSubBlockEnd.gif        }

476ExpandedSubBlockEnd.gif    }

477ExpandedBlockEnd.gif}

代码时序图如下:

 
Sequence_Diagram__Sequence__PutEntityProperty__PutEntityProperty__PutEntityProperty.jpg

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

转载于:https://www.cnblogs.com/afritxia2008/archive/2008/07/06/1236860.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值