• 使用CodeDom提高ORM性能


    下载本文代码:https://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    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类用白色表示。具体代码如下:

     1using System;
     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:

     1using System;
     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:

      1#undef _Debug  // 用于调试
      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[0as 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(可以运行该测试文件)

  • 相关阅读:
    Doc2Vec -- "tag '23943' not seen in training corpus/invalid" 错误
    一行代码书写的神奇
    MySQL8.0-Public Key Retrieval is not allowed
    Dubbo-admin-2.7上下(新旧)版本打包发布到Liunx服务器
    Git遇到SSL错误:fatal: unable to access 'https://***************': OpenSSL SSL_read: Connection was reset, errno 10054
    Google浏览器快捷键
    Windows快捷键
    IDEA快捷键
    LocalDateTime
    数组
  • 原文地址:https://www.cnblogs.com/afritxia2008/p/1236860.html
Copyright © 2020-2023  润新知