|
|
|
|
|
使用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} 不支持Flash
|