/// <summary> /// 初始化 <see cref="ColumnExpressionVisitor"/> 类的新实例 /// </summary> /// <param name="ag">表别名解析器</param> /// <param name="builder">SQL 语句生成器</param> /// <param name="tree">查询语义</param> public ColumnExpressionVisitor(AliasGenerator ag, ISqlBuilder builder, DbQuerySelectTree tree) : base(ag, builder) { _ag = ag; _builder = builder; _groupBy = tree.GroupBy; _includes = tree.Includes; _selectedColumns = new ColumnDescriptorCollection(); _visitedStack = base.VisitedStack; }
/// <summary> /// 生成实体映射委托 /// </summary> /// <param name="type">实体类型</param> /// <param name="reader">数据读取器</param> /// <param name="columns">字段列描述</param> /// <param name="start">开始索引</param> /// <param name="end">结束索引</param> /// <returns></returns> public Func <IDataRecord, object> GetTypeDeserializer(Type type, IDataRecord reader, ColumnDescriptorCollection columns = null, int start = 0, int?end = null) { //// specify a new assembly name //var assemblyName = new AssemblyName("Riz.Deserialize"); //// create assembly builder //var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); //// create module builder //var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll", true); //// create type builder for a class //var typeBuilder = moduleBuilder.DefineType("Riz.Deserialize.Deserializer", TypeAttributes.Public); //// create method builder //var methodBuilder = typeBuilder.DefineMethod("GetModel", // MethodAttributes.Public | MethodAttributes.Static, // typeof(object), // new Type[] { typeof(IDataRecord) // }); TypeRuntimeInfo typeRuntime = TypeRuntimeInfoCache.GetRuntimeInfo(type); DynamicMethod dynamicMethod = new DynamicMethod(string.Format("Deserialize{0}", Guid.NewGuid()), typeof(object), new Type[] { typeof(IDataRecord) }, true); //ILGenerator il = methodBuilder.GetILGenerator(); ILGenerator il = dynamicMethod.GetILGenerator(); il.DeclareLocal(typeof(int)); // [0] int index il.DeclareLocal(type); // [1] {type} il.Emit(OpCodes.Ldc_I4_0); il.Emit(OpCodes.Stloc_0); // 有参构造函数 ConstructorInfo specializedConstructor = null; if (type.IsValueType) { // 如果是值类型,则将值类型设置为空或者0 il.Emit(OpCodes.Ldloca_S, (byte)1); il.Emit(OpCodes.Initobj, type); } else { var ctor = typeRuntime.Constructor.Member; if (ctor.GetParameters().Length > 0) { specializedConstructor = ctor; } else { // 如果不是匿名类或者只有无参构造函数,则new一个对象 il.Emit(OpCodes.Newobj, ctor); il.Emit(OpCodes.Stloc_1); // [1] {type}=new {type} } } // try ##### il.BeginExceptionBlock(); if (specializedConstructor == null) { il.Emit(OpCodes.Ldloc_1); // [target] } // stack is now [target] Label finishLabel = il.DefineLabel(); Label loadNullLabel = il.DefineLabel(); int enumDeclareLocal = -1; if (end == null) { end = reader.FieldCount; } for (int index = start; index < end; index++) { // 找出对应DataReader中的字段名 string memberName = reader.GetName(index); if (columns != null) { ColumnDescriptor column = null; columns.TryGetValue(memberName, out column); memberName = column != null ? column.Name : string.Empty; } // 本地变量赋值 il.Emit(OpCodes.Ldc_I4, index); // [target][index] il.Emit(OpCodes.Stloc_0); // [target] // 如果导航属性分割列=DbNull,那么此导航属性赋空值 if (memberName == AppConst.NAVIGATION_SPLITON_NAME) { il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, index); il.Emit(OpCodes.Callvirt, _isDBNull); il.Emit(OpCodes.Brtrue_S, loadNullLabel); } var m = typeRuntime.GetMember(memberName) as FieldAccessorBase; if (m == null) { continue; } if (specializedConstructor == null) { il.Emit(OpCodes.Dup); // stack is now [target][target] } // 数据字段类型 Type readerFieldType = reader.GetFieldType(index); Type realReaderFieldType = readerFieldType; // 实体属性类型 Type entityFieldType = m.CLRType; MethodInfo getFieldValue = this.GetReaderMethod(readerFieldType, entityFieldType, ref realReaderFieldType); if (readerFieldType != realReaderFieldType) { readerFieldType = realReaderFieldType; } Label isDbNullLabel = il.DefineLabel(); Label nextLoopLabel = il.DefineLabel(); // 判断字段是否是 DbNull il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ldc_I4, index); il.Emit(OpCodes.Callvirt, _isDBNull); il.Emit(OpCodes.Brtrue, isDbNullLabel); // =>DataReader.Getxx(index) il.Emit(OpCodes.Ldarg_0); // stack is now [target][target][reader] if (getFieldValue.DeclaringType != typeof(IDataRecord)) { il.Emit(OpCodes.Castclass, getFieldValue.DeclaringType); // (SqlDataReader)IDataReader } il.Emit(OpCodes.Ldc_I4, index); // stack is now [target][target][reader][index] il.Emit(OpCodes.Callvirt, getFieldValue); // stack is now [target][target][value-or-object] if (entityFieldType == typeof(char) || entityFieldType == typeof(char?)) { il.EmitCall(OpCodes.Call, entityFieldType == typeof(char) ? _readChar : _readNullChar, null); // stack is now [target][target][typed-value] } else { // unbox nullable enums as the primitive, i.e. byte etc var nullUnderlyingType = Nullable.GetUnderlyingType(entityFieldType); var unboxType = nullUnderlyingType != null && nullUnderlyingType.IsEnum ? nullUnderlyingType : entityFieldType; if (unboxType.IsEnum) { Type numericType = Enum.GetUnderlyingType(unboxType); if (readerFieldType != typeof(string)) { ConvertBoxedStack(il, readerFieldType, unboxType, numericType); } else { if (enumDeclareLocal == -1) { enumDeclareLocal = il.DeclareLocal(typeof(string)).LocalIndex; } il.Emit(OpCodes.Castclass, typeof(string)); // stack is now [target][target][string] il.StoreLocal(enumDeclareLocal); // stack is now [target][target] il.Emit(OpCodes.Ldtoken, unboxType); // stack is now [target][target][enum-type-token] il.EmitCall(OpCodes.Call, _typeFromHandle, null); // stack is now [target][target][enum-type] il.LoadLocal(enumDeclareLocal); // stack is now [target][target][enum-type][string] il.Emit(OpCodes.Ldc_I4_1); // stack is now [target][target][enum-type][string][true] il.EmitCall(OpCodes.Call, _enumParse, null); // stack is now [target][target][enum-as-object] il.Emit(OpCodes.Unbox_Any, unboxType); // stack is now [target][target][typed-value] } // new Nullable<TValue>(TValue) if (nullUnderlyingType != null) { EmitNewNullable(il, entityFieldType); // stack is now [target][target][typed-value] } } else if (entityFieldType.FullName == _linqBinaryName) { var ctor = entityFieldType.GetConstructor(new Type[] { typeof(byte[]) }); il.Emit(OpCodes.Unbox_Any, typeof(byte[])); // stack is now [target][target][byte-array] il.Emit(OpCodes.Newobj, ctor); // stack is now [target][target][binary] } else { bool noBoxed = readerFieldType == unboxType || readerFieldType == nullUnderlyingType; // myFieldType和实体属性类型一致, 如果用 DataReader.GetValue,则要强制转换{object}为实体属性定义的类型 bool useCast = noBoxed && getFieldValue == _getValue && unboxType != typeof(object); if (useCast) { il.EmitCast(nullUnderlyingType ?? unboxType); // stack is now [target][target][typed-value] } // myFieldType和实体属性类型不一致,需要做类型转换 if (!noBoxed) { if (getFieldValue == _getValue && readerFieldType.IsValueType) { il.Emit(OpCodes.Unbox_Any, readerFieldType); // stack is now [target][target][value] } // not a direct match; need to tweak the unbox ConvertBoxedStack(il, readerFieldType, nullUnderlyingType ?? unboxType, null); } // new Nullable<TValue>(TValue) if (nullUnderlyingType != null) { EmitNewNullable(il, entityFieldType); // stack is now [target][target][typed-value] } } } if (specializedConstructor == null) { // Store the value in the property/field if (m.MemberType == MemberTypes.Field) { il.Emit(OpCodes.Stfld, m.Member as FieldInfo); // stack is now [target] } else { MethodInfo setMethod = (m as PropertyAccessor).Member.GetSetMethod(true); il.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, setMethod);// stack is now [target] } } il.Emit(OpCodes.Br_S, nextLoopLabel); // stack is now [target] il.MarkLabel(isDbNullLabel); // incoming stack: [target][target] if (specializedConstructor == null) { il.Emit(OpCodes.Pop); // stack is now [target] } else { // DbNull,将NULL或者0推到栈顶 if (!entityFieldType.IsValueType) { il.Emit(OpCodes.Ldnull); } else { int localIndex = il.DeclareLocal(entityFieldType).LocalIndex; il.LoadLocalAddress(localIndex); il.Emit(OpCodes.Initobj, entityFieldType); il.LoadLocal(localIndex); } } il.MarkLabel(nextLoopLabel); } if (specializedConstructor != null) { il.Emit(OpCodes.Newobj, specializedConstructor); } il.Emit(OpCodes.Stloc_1); // stack is empty // 直接跳到结束标签返回实体 il.Emit(OpCodes.Br, finishLabel); // 将 null 赋值给实体 il.MarkLabel(loadNullLabel); il.Emit(OpCodes.Pop); il.Emit(OpCodes.Ldnull); il.Emit(OpCodes.Stloc_1); il.MarkLabel(finishLabel); il.BeginCatchBlock(typeof(Exception)); // stack is Exception il.Emit(OpCodes.Ldloc_0); // stack is Exception, index il.Emit(OpCodes.Ldarg_0); // stack is Exception, index, reader il.EmitCall(OpCodes.Call, _throwException, null); il.EndExceptionBlock(); il.Emit(OpCodes.Ldloc_1); // stack is [rval] il.Emit(OpCodes.Ret); //// then create the whole class type //typeBuilder.CreateType(); //// save assembly //assemblyBuilder.Save(assemblyName.Name + ".dll"); return((Func <IDataRecord, object>)dynamicMethod.CreateDelegate(typeof(Func <IDataRecord, object>))); }