C#发现之旅:基于反射和动态编译的快速ORM框架(上)
2010-09-30 21:08:28 来源:WEB开发网.NET框架自己包含了一个C#代码编译器,它的文件名是CSC.EXE,在.NET框架的安装目录下,在笔者的电脑中其路径是 C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\csc.exe 或者 C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\csc.exe ,它是一个基于命令行的编辑器,能将C#代码编译生成EXE或者DLL文件。关于C#代码编译器可参考MSDN中的相关说明。
快速ORM框架的控制模块接受应用程序的请求,首先检查实体类型注册列表,若列表中没有找到相应的RecordORMHelper对象,则调用代码生成器生成代码,然后调用C#代码编译器编译生成临时的程序集,然后加载临时程序集,使用反射(调用System.Reflection.Assembly.GetType函数)找到其中所有的的RecordORMHelper类型,然后根据类型动态的创建对象实例,并填充到实体类型注册列表。最后调用RecordORMHelper预定的接口来实现ORM功能。
若我们在使用快速ORM框架前,将所有可能要用到的实体对象类型添加到实体类型注册列表中,则快速ORM框架会生成一个临时程序集,但我们是陆陆续续的往ORM框架注册实体对象类型,则快速ORM框架内部可能会多次调用代码生成器和代码编译器来生成临时程序集,这样最后会生成多个临时程序集。一般的建议在使用框架前将向ORM框架注册所有可能用到的实体对象类型,这样框架只会执行一次动态编译的操作。
基础类型RecordORMHelper
本类型属于ORM框架的底层模块。其代码为
public abstract class RecordORMHelper
{
/// <summary>
/// 对象操作的数据表名称
/// </summary>
public abstract string TableName
{
get ;
}
/// <summary>
/// 从数据读取器读取数据创建一个记录对象
/// </summary>
/// <param name="reader">数据读取器</param>
/// <returns>读取的数据</returns>
public object ReadRecord( System.Data.IDataReader reader )
{
int[] indexs = GetFieldIndexs( reader );
return InnerReadRecord( reader ,indexs );
}
/// <summary>
/// 从数据读取器读取数据创建若干个记录对象
/// </summary>
/// <param name="reader">数据读取器</param>
/// <param name="MaxRecordCount">允许读取的最大的记录个数,为0则无限制</param>
/// <returns>读取的数据对象列表</returns>
public System.Collections.ArrayList ReadRecords( System.Data.IDataReader reader , int MaxRecordCount )
{
System.Collections.ArrayList list = new System.Collections.ArrayList();
int[] indexs = GetFieldIndexs( reader );
while( reader.Read())
{
object record = InnerReadRecord( reader , indexs );
list.Add( record );
if( MaxRecordCount > 0 && list.Count >= MaxRecordCount )
{
break;
}
}//while
return list ;
}
/// <summary>
/// 从一个数据读取器中读取一条记录对象,必须重载
/// </summary>
/// <param name="reader">数据读取器</param>
/// <param name="FieldIndexs">字段序号列表</param>
/// <returns>读取的记录对象</returns>
protected abstract object InnerReadRecord( System.Data.IDataReader reader , int[] FieldIndexs );
/// <summary>
/// 为删除记录而初始化数据库命令对象
/// </summary>
/// <param name="cmd">数据库命令对象</param>
/// <param name="objRecord">实体对象实例</param>
/// <returns>添加的SQL参数个数</returns>
public abstract int FillDeleteCommand( System.Data.IDbCommand cmd , object objRecord );
/// <summary>
/// 为插入记录而初始化数据库命令对象
/// </summary>
/// <param name="cmd">数据库命令对象</param>
/// <param name="objRecord">实体对象实例</param>
/// <returns>添加的SQL参数个数</returns>
public abstract int FillInsertCommand( System.Data.IDbCommand cmd , object objRecord );
/// <summary>
/// 为更新数据库记录而初始化数据库命令对象
/// </summary>
/// <param name="cmd">数据库命令对象</param>
/// <param name="objRecord">实体对象实例</param>
/// <returns>添加的SQL参数个数</returns>
public abstract int FillUpdateCommand( System.Data.IDbCommand cmd , object objRecord );
/// <summary>
/// 字段列表数组
/// </summary>
protected abstract string[] RecordFieldNames
{
get ;
}
/// <summary>
/// 针对特定的数据读取器获得实体对象的各个属性对应的数据栏目的编号
/// </summary>
/// <param name="reader">数据读取器</param>
/// <returns>编号列表</returns>
private int[] GetFieldIndexs( System.Data.IDataReader reader )
{
if( reader == null )
{
throw new ArgumentNullException("reader");
}
string[] FieldNames = this.RecordFieldNames ;
int[] indexs = new int[ FieldNames.Length ] ;
int FieldCount = reader.FieldCount ;
string[] names = new string[ FieldCount ] ;
for( int iCount = 0 ; iCount < FieldCount ; iCount ++ )
{
names[ iCount ] = reader.GetName( iCount ) ;
}
for( int iCount = 0 ; iCount < indexs.Length ; iCount ++ )
{
indexs[ iCount ] = -1 ;
string name = FieldNames[ iCount ] ;
for( int iCount2 = 0 ; iCount2 < FieldCount ; iCount2 ++ )
{
if( EqualsFieldName( name , names[ iCount2 ] ))
{
indexs[ iCount ] = iCount2 ;
break;
}
}
}
for( int iCount = 0 ; iCount < FieldCount ; iCount ++ )
{
string name = reader.GetName( iCount );
for( int iCount2 = 0 ; iCount2 < indexs.Length ; iCount2 ++ )
{
if( EqualsFieldName( name , FieldNames[ iCount2 ] ))
{
indexs[ iCount2 ] = iCount ;
}
}
}
return indexs ;
}
/// <summary>
/// 连接多个字符串,各个字符串之间用逗号分隔,本函数会在动态生成的派生类中使用
/// </summary>
/// <param name="strs">字符串集合</param>
/// <returns>连接所得的大字符串</returns>
protected string ConcatStrings( System.Collections.IEnumerable strs )
{
System.Text.StringBuilder myStr = new System.Text.StringBuilder();
foreach( string str in strs )
{
if( myStr.Length > 0 )
{
myStr.Append(",");
}
myStr.Append( str );
}//foreach
return myStr.ToString();
}
/// <summary>
/// 判断两个字段名是否等价
/// </summary>
/// <param name="name1">字段名1</param>
/// <param name="name2">字段名2</param>
/// <returns>true:两个字段名等价 false:字段名不相同</returns>
private bool EqualsFieldName( string name1 , string name2 )
{
if( name1 == null || name2 == null )
{
throw new ArgumentNullException("name1 or name2");
}
name1 = name1.Trim();
name2 = name2.Trim();
// 进行不区分大小写的比较
if( string.Compare( name1 , name2 , true ) == 0 )
{
return true ;
}
int index = name1.IndexOf(".");
if( index > 0 )
{
name1 = name1.Substring( index + 1 ).Trim();
}
index = name2.IndexOf(".");
if( index > 0 )
{
name2 = name2.Substring( index + 1 ).Trim();
}
return string.Compare( name1 , name2 , true ) == 0 ;
}
#region 从数据库读取的原始数据转换为指定数据类型的函数群,本函数会在动态生成的派生类中使用
protected byte ConvertToByte( object v , byte DefaultValue )
{
if( v == null || DBNull.Value.Equals( v ))
return DefaultValue ;
else
return Convert.ToByte( v );
}
protected sbyte ConvertToSByte( object v , sbyte DefaultValue )
{
if( v == null || DBNull.Value.Equals( v ))
return DefaultValue ;
else
return Convert.ToSByte( v );
}
更多精彩
赞助商链接