使用CodeDom提高ORM性能

http://www.sina.com.cn 2008年07月07日 14:54  IT168.com

【IT168技术文档】

  ORM(Object/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[0] as DataColumnAttribute;
22
23            int ordinal = -1;
24
25            try
26            {
27                // 获取数据列序号
28                ordinal = dr.GetOrdinal(colAttr.ColumnName);
29            }
30            catch (Exception ex)
31            {
32                throw new MappingException(
33                    String.Format("{0} 未找到该数据列( Cannot Found this Column {0} )", colAttr.ColumnName), ex);
34            }
35
36            // 获取数据列值
37            object objValue = dr.GetValue(ordinal);
38
39            if (objValue is DBNull)
40            {
41                // 将 null 值设置到属性
42                propInfo.SetValue(objEntity, null, null);
43            }
44            else
45            {
46                // 将值设置到属性
47                propInfo.SetValue(objEntity, objValue, null);
48            }
49        }
50    }
51

  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}
  设置器工厂类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}


Powered By Google
不支持Flash
·城市对话改革30年 ·新浪城市同心联动 ·诚招合作伙伴 ·企业邮箱畅通无阻