예제 #1
0
        public static string TypeToDbTypeStatement(EntityPropertyDef propertyDef, EngineType engineType)
        {
            //查看属性自定义
            if (propertyDef.TypeConverter != null)
            {
                return(propertyDef.TypeConverter.Statement);
            }

            Type trueType = propertyDef.NullableUnderlyingType ?? propertyDef.Type;

            //查看全局TypeConvert
            ConverterInfo?converterInfo = GetGlobalConverterInfo(trueType, engineType);

            if (converterInfo != null)
            {
                return(converterInfo.Statement);
            }

            //默认处理
            if (trueType.IsEnum)
            {
                return(GetGlobalConverterInfo(typeof(string), engineType) !.Statement);
            }
            throw Exceptions.EntityHasNotSupportedPropertyType(type: propertyDef.EntityDef.EntityFullName, propertyTypeName: (propertyDef.NullableUnderlyingType ?? propertyDef.Type).FullName, propertyName: propertyDef.Name);
        }
예제 #2
0
        public static object TypeValueToDbValue(object?typeValue, EntityPropertyDef propertyDef, EngineType engineType)
        {
            if (typeValue == null)
            {
                return(DBNull.Value);
            }

            //查看当前Property的TypeConvert
            if (propertyDef.TypeConverter != null)
            {
                return(propertyDef.TypeConverter.TypeValueToDbValue(typeValue, propertyDef.Type));
            }

            Type trueType = propertyDef.NullableUnderlyingType ?? propertyDef.Type;

            //查看全局TypeConvert

            ITypeConverter?globalConverter = GetGlobalTypeConverter(trueType, engineType);

            if (globalConverter != null)
            {
                return(globalConverter.TypeValueToDbValue(typeValue, trueType));
            }

            //默认
            if (trueType.IsEnum)
            {
                return(typeValue.ToString() !);
            }

            return(typeValue);
        }
예제 #3
0
        public static string TypeValueToDbValueStatement(object?typeValue, bool quotedIfNeed, EngineType engineType)
        {
            if (typeValue == null)
            {
                return("null");
            }

            Type type = typeValue.GetType();
            EntityPropertyDef propertyDef = new EntityPropertyDef
            {
                Type = type,
                NullableUnderlyingType = Nullable.GetUnderlyingType(type),
                TypeConverter          = null
            };

            object dbValue = TypeValueToDbValue(typeValue, propertyDef, engineType);

            string statement = dbValue switch
            {
                //null => "null",
                //Enum e => e.ToString(),
                DBNull _ => "null",
                DateTime _ => throw Exceptions.UseDateTimeOffsetOnly(),
                      DateTimeOffset dt => dt.ToString(@"yyyy\-MM\-dd HH\:mm\:ss.FFFFFFFzzz", GlobalSettings.Culture),
                      bool b => b ? "1" : "0",
                      _ => dbValue.ToString() !
            };

            if (!quotedIfNeed || statement == "null" || !SqlHelper.IsValueNeedQuoted(dbValue !.GetType()))
            {
                return(statement);
            }

            return(SqlHelper.GetQuoted(statement));
        }
예제 #4
0
        public static string CreateDeleteSql(EntityDef entityDef)
        {
            EntityPropertyDef deletedProperty = entityDef.GetPropertyDef(nameof(Entity.Deleted)) !;
            EntityPropertyDef versionProperty = entityDef.GetPropertyDef(nameof(Entity.Version)) !;

            return($"update {entityDef.DbTableReservedName} set {versionProperty.DbReservedName}={versionProperty.DbReservedName}+1, {deletedProperty.DbReservedName}=1");
        }
예제 #5
0
        public static string CreateUpdateEntitySql(EntityDef entityDef, int number = 0)
        {
            StringBuilder args = new StringBuilder();

            foreach (EntityPropertyDef propertyInfo in entityDef.PropertyDefs)
            {
                if (propertyInfo.IsPrimaryKey)
                {
                    continue;
                }

                args.Append($" {propertyInfo.DbReservedName}={propertyInfo.DbParameterizedName}_{number},");
            }

            args.RemoveLast();

            EntityPropertyDef primaryKeyProperty = entityDef.PrimaryKeyPropertyDef;
            EntityPropertyDef deletedProperty    = entityDef.GetPropertyDef(nameof(Entity.Deleted)) !;
            EntityPropertyDef versionProperty    = entityDef.GetPropertyDef(nameof(Entity.Version)) !;

            StringBuilder where = new StringBuilder();

            where.Append($"{primaryKeyProperty.DbReservedName}={primaryKeyProperty.DbParameterizedName}_{number} AND ");
            where.Append($"{versionProperty.DbReservedName}={versionProperty.DbParameterizedName}_{number} - 1 AND ");
            where.Append($"{deletedProperty.DbReservedName}=0");

            return($"UPDATE {entityDef.DbTableReservedName} SET {args} WHERE {where};");
        }
예제 #6
0
        public static object?DbValueToTypeValue(object dbValue, EntityPropertyDef propertyDef, EngineType engineType)  //Type targetType)
        {
            Type dbValueType = dbValue.GetType();

            if (dbValueType == typeof(DBNull))
            {
                return(null);
            }

            //查看属性TypeConverter
            if (propertyDef.TypeConverter != null)
            {
                return(propertyDef.TypeConverter.DbValueToTypeValue(dbValue, propertyDef.Type));
            }

            Type   trueType = propertyDef.NullableUnderlyingType ?? propertyDef.Type;
            object?typeValue;

            //查看全局TypeConverter
            ITypeConverter?globalConverter = GetGlobalTypeConverter(trueType, engineType);

            if (globalConverter != null)
            {
                typeValue = globalConverter.DbValueToTypeValue(dbValue, trueType);
            }
            else
            {
                //默认

                if (trueType.IsEnum)
                {
                    typeValue = Enum.Parse(trueType, dbValue.ToString() !, true);
                }
                else if (trueType != dbValueType)
                {
                    typeValue = Convert.ChangeType(dbValue, trueType, GlobalSettings.Culture);
                }
                else
                {
                    typeValue = dbValue;
                }
            }

            //处理Nullable
            if (propertyDef.NullableUnderlyingType == null)
            {
                return(typeValue);
            }

            ConstructorInfo?ctor = propertyDef.Type.GetConstructor(new Type[] { propertyDef.NullableUnderlyingType });

            return(ctor !.Invoke(new object?[] { typeValue }));
        }
예제 #7
0
        public async Task Test_EntityMapperPerformanceAsync(int index)
        {
            index++;



            IDatabase database = _sqlite;

            IList <BookEntity_Client>?books = Mocker.GetBooks_Client(500);

            TransactionContext?trans = await _sqlIteTransaction.BeginTransactionAsync <BookEntity_Client>().ConfigureAwait(false);

            IEnumerable <BookEntity_Client> re = await database.RetrieveAsync <BookEntity_Client>(b => b.Deleted, trans).ConfigureAwait(false);

            await database.AddAsync <BookEntity_Client>(Mocker.GetBooks_Client(1)[0], "", trans).ConfigureAwait(false);

            try
            {
                //await database.AddAsync<BookEntity>(books[0], "", trans);

                await database.BatchAddAsync(books, "x", trans).ConfigureAwait(false);

                await _sqlIteTransaction.CommitAsync(trans).ConfigureAwait(false);
            }
            catch
            {
                await _sqlIteTransaction.RollbackAsync(trans).ConfigureAwait(false);
            }


            Stopwatch stopwatch = new Stopwatch();

            using SqliteConnection mySqlConnection = new SqliteConnection("Data Source=sqlite_test2.db");



            //time = 0;
            int loop = 10;

            TimeSpan time0 = TimeSpan.Zero, time1 = TimeSpan.Zero, time2 = TimeSpan.Zero, time3 = TimeSpan.Zero;

            for (int cur = 0; cur < loop; ++cur)
            {
                await mySqlConnection.OpenAsync().ConfigureAwait(false);


                using SqliteCommand command0 = new SqliteCommand("select * from tb_bookentity_client limit 1000", mySqlConnection);

                SqliteDataReader?reader0 = await command0.ExecuteReaderAsync().ConfigureAwait(false);

                List <BookEntity_Client> list1 = new List <BookEntity_Client>();
                List <BookEntity_Client> list2 = new List <BookEntity_Client>();
                List <BookEntity_Client> list3 = new List <BookEntity_Client>();

                int len = reader0.FieldCount;
                EntityPropertyDef[] propertyDefs = new EntityPropertyDef[len];
                MethodInfo[]        setMethods   = new MethodInfo[len];

                EntityDef definition = EntityDefFactory.GetDef <BookEntity_Client>() !;

                for (int i = 0; i < len; ++i)
                {
                    propertyDefs[i] = definition.GetPropertyDef(reader0.GetName(i)) !;
                    setMethods[i]   = propertyDefs[i].SetMethod;
                }


                Func <IDataReader, object> mapper1 = EntityMapperDelegateCreator.CreateToEntityDelegate(definition, reader0, 0, definition.FieldCount, false, Database.Engine.EngineType.SQLite);


                //Warning: 如果用Dapper,小心DateTimeOffset的存储,会丢失offset,然后转回来时候,会加上当地时间的offset
                TypeHandlerHelper.AddTypeHandlerImpl(typeof(DateTimeOffset), new DateTimeOffsetTypeHandler(), false);
                Func <IDataReader, object> mapper2 = DataReaderTypeMapper.GetTypeDeserializerImpl(typeof(BookEntity_Client), reader0);



                Stopwatch stopwatch1 = new Stopwatch();
                Stopwatch stopwatch2 = new Stopwatch();
                Stopwatch stopwatch3 = new Stopwatch();

                while (reader0.Read())
                {
                    stopwatch1.Start();

                    object obj1 = mapper1(reader0);

                    list1.Add((BookEntity_Client)obj1);
                    stopwatch1.Stop();



                    stopwatch2.Start();
                    object obj2 = mapper2(reader0);

                    list2.Add((BookEntity_Client)obj2);
                    stopwatch2.Stop();


                    stopwatch3.Start();

                    BookEntity_Client item = new BookEntity_Client();

                    for (int i = 0; i < len; ++i)
                    {
                        EntityPropertyDef property = propertyDefs[i];

                        object?value = TypeConvert.DbValueToTypeValue(reader0[i], property, Database.Engine.EngineType.SQLite);

                        if (value != null)
                        {
                            setMethods[i].Invoke(item, new object?[] { value });
                        }
                    }

                    list3.Add(item);

                    stopwatch3.Stop();
                }

                time1 += stopwatch1.Elapsed;
                time2 += stopwatch2.Elapsed;
                time3 += stopwatch3.Elapsed;

                await reader0.DisposeAsync().ConfigureAwait(false);

                command0.Dispose();

                await mySqlConnection.CloseAsync().ConfigureAwait(false);
            }

            _output.WriteLine("Emit Coding : " + (time1.TotalMilliseconds / (loop * 1.0)).ToString(CultureInfo.InvariantCulture));
            _output.WriteLine("Dapper : " + (time2.TotalMilliseconds / (loop * 1.0)).ToString(CultureInfo.InvariantCulture));
            _output.WriteLine("Reflection : " + (time3.TotalMilliseconds / (loop * 1.0)).ToString(CultureInfo.InvariantCulture));
        }
예제 #8
0
        public static string CreateAddOrUpdateSql(EntityDef entityDef, EngineType engineType, bool returnId, int number = 0)
        {
            StringBuilder addArgs     = new StringBuilder();
            StringBuilder selectArgs  = new StringBuilder();
            StringBuilder addValues   = new StringBuilder();
            StringBuilder updatePairs = new StringBuilder();

            foreach (EntityPropertyDef propertyDef in entityDef.PropertyDefs)
            {
                if (returnId)
                {
                    selectArgs.Append($"{propertyDef.DbReservedName},");
                }

                if (propertyDef.IsAutoIncrementPrimaryKey)
                {
                    continue;
                }

                addArgs.Append($"{propertyDef.DbReservedName},");
                addValues.Append($"{propertyDef.DbParameterizedName}_{number},");

                if (propertyDef.IsPrimaryKey)
                {
                    continue;
                }

                if (propertyDef.Name == nameof(Entity.Version) || propertyDef.Name == nameof(Entity.CreateTime))
                {
                    continue;
                }

                updatePairs.Append($" {propertyDef.DbReservedName}={propertyDef.DbParameterizedName}_{number},");
            }

            EntityPropertyDef versionProperty = entityDef.GetPropertyDef(nameof(Entity.Version)) !;

            updatePairs.Append($"{versionProperty.DbReservedName}={versionProperty.DbReservedName} + 1");

            if (returnId)
            {
                selectArgs.RemoveLast();
            }

            addValues.RemoveLast();
            addArgs.RemoveLast();

            EntityPropertyDef primaryKeyProperty = entityDef.PrimaryKeyPropertyDef;

            string sql = $"insert into {entityDef.DbTableReservedName}({addArgs}) values({addValues}) {OnDuplicateKeyUpdateStatement(engineType, primaryKeyProperty)} {updatePairs};";

            if (returnId)
            {
                if (entityDef.IsIdAutoIncrement)
                {
                    sql += $"select {selectArgs} from {entityDef.DbTableReservedName} where {primaryKeyProperty.DbReservedName} = {GetLastInsertIdStatement(engineType)};";
                }
                else
                {
                    sql += $"select {selectArgs} from {entityDef.DbTableReservedName} where {primaryKeyProperty.DbReservedName} = {primaryKeyProperty.DbParameterizedName}_{number};";
                }
            }

            return(sql);
        }
예제 #9
0
        /// <summary>
        /// EmitEntityMapper
        /// </summary>
        /// <param name="def"></param>
        /// <param name="reader"></param>
        /// <param name="startIndex"></param>
        /// <param name="length"></param>
        /// <param name="returnNullIfFirstNull"></param>
        /// <param name="engineType"></param>
        /// <param name="il"></param>
        /// <exception cref="DatabaseException"></exception>
        private static void EmitEntityMapper(EntityDef def, IDataReader reader, int startIndex, int length, bool returnNullIfFirstNull, EngineType engineType, ILGenerator il)
        {
            try
            {
                List <EntityPropertyDef> propertyDefs = new List <EntityPropertyDef>();

                for (int i = startIndex; i < startIndex + length; ++i)
                {
                    propertyDefs.Add(def.GetPropertyDef(reader.GetName(i))
                                     ?? throw Exceptions.EntityError(def.EntityFullName, reader.GetName(i), "Lack PropertyDef"));
                }

                LocalBuilder returnValueLocal    = il.DeclareLocal(def.EntityType);
                LocalBuilder enumStringTempLocal = il.DeclareLocal(typeof(string));
                LocalBuilder timespanZeroLocal   = il.DeclareLocal(typeof(TimeSpan));
                LocalBuilder entityTypeLocal     = il.DeclareLocal(typeof(Type));

                System.Reflection.Emit.Label allFinished = il.DefineLabel();

                ConstructorInfo ctor = def.EntityType.GetDefaultConstructor()
                                       ?? throw Exceptions.EntityError(def.EntityFullName, "", "实体没有默认构造函数");

                il.Emit(OpCodes.Ldtoken, def.EntityType);
                il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null);
                il.Emit(OpCodes.Stloc, entityTypeLocal);

                il.Emit(OpCodes.Newobj, ctor);
                //emitter.NewObject(ctor);
                il.Emit(OpCodes.Stloc, returnValueLocal);
                //emitter.StoreLocal(returnValueLocal);
                il.Emit(OpCodes.Ldloc, returnValueLocal);
                //emitter.LoadLocal(returnValueLocal); // [target]

                bool firstProperty = true;

                for (int index = 0; index < propertyDefs.Count; ++index)
                {
                    bool hasConverter = false;

                    System.Reflection.Emit.Label dbNullLabel = il.DefineLabel();
                    System.Reflection.Emit.Label finishLable = il.DefineLabel();

                    Type dbValueType = reader.GetFieldType(index + startIndex);

                    il.Emit(OpCodes.Dup);
                    //emitter.Duplicate(); // stack is now [target][target]

                    EntityPropertyDef propertyDef = propertyDefs[index];
                    Type trueType = propertyDef.NullableUnderlyingType ?? propertyDef.Type;

                    //======属性自定义Converter
                    if (propertyDef.TypeConverter != null)
                    {
                        //il.Emit(OpCodes.Ldtoken, def.EntityType);
                        //il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null);
                        il.Emit(OpCodes.Ldloc, entityTypeLocal);


                        il.Emit(OpCodes.Ldstr, propertyDef.Name);
                        //emitter.LoadConstant(propertyDef.PropertyInfo.Name);
                        // stack is now [target][target][EntityType][PropertyName]
                        il.EmitCall(OpCodes.Call, _getPropertyTypeConverterMethod, null);
                        //emitter.Call(typeof(DatabaseEntityDef).GetMethod(nameof(DatabaseEntityDef.OnlyForEmitGetPropertyTypeConverter)));
                        // stack is now [target][target][TypeConverter]

                        hasConverter = true;
                    }
                    else
                    {
                        //======全局Converter

                        ITypeConverter?globalTypeConverter = TypeConvert.GetGlobalTypeConverter(trueType, engineType);

                        if (globalTypeConverter != null)
                        {
                            il.Emit(OpCodes.Ldtoken, trueType);
                            il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null);
                            EmitInt32(il, (int)engineType);

                            il.EmitCall(OpCodes.Call, _getGlobalTypeConverterMethod, null);
                            //stack is now [target][target][TypeConverter]

                            hasConverter = true;
                        }
                    }

                    //===获取数据库值=========================================================================

                    il.Emit(OpCodes.Ldarg_0);
                    //emitter.LoadArgument(0);// stack is now [...][reader]
                    EmitInt32(il, index + startIndex);
                    //emitter.LoadConstant(index); // stack is now [...][reader][index]
                    il.EmitCall(OpCodes.Callvirt, _dataReaderGetItemMethod, null);
                    //emitter.CallVirtual(ReflectionHelper.GetItem);// stack is now [...][value-as-object]

                    //处理Null
                    il.Emit(OpCodes.Dup);
                    //emitter.Duplicate(); //stack is now [...][value-as-object][value-as-object]
                    il.Emit(OpCodes.Isinst, typeof(DBNull));
                    //emitter.IsInstance(typeof(DBNull));//stack is now [...][value-as-object][DbNull/null]
                    il.Emit(OpCodes.Brtrue_S, dbNullLabel);
                    //emitter.BranchIfTrue(dbNullLabel);//stack is now [...][value-as-object]

                    #region DbValueToTypeValue,逻辑同DatabaseConverty.DbValueToTypeValue一致
                    if (propertyDef.TypeConverter != null)
                    {
                        // stack is now [target][target][TypeConverter][value-as-object]
                        il.Emit(OpCodes.Ldtoken, propertyDef.Type);
                        il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null);
                        //stack is now [target][target][TypeConverter][value-as-object][propertyType]
                        il.EmitCall(OpCodes.Callvirt, _getTypeConverterDbValueToTypeValueMethod, null);
                        //emitter.CallVirtual(typeof(DatabaseTypeConverter).GetMethod(nameof(DatabaseTypeConverter.DbValueToTypeValue)));

                        il.Emit(OpCodes.Unbox_Any, propertyDef.Type);
                        //emitter.UnboxAny(propertyDef.Type);

                        // stack is now [target][target][TypeValue]
                    }
                    else
                    {
                        if (hasConverter)
                        {
                            //全局Converter

                            // stack is now [target][target][TypeConverter][value-as-object]
                            il.Emit(OpCodes.Ldtoken, trueType);
                            il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null);
                            //stack is now [target][target][TypeConverter][value-as-object][trueType]
                            il.EmitCall(OpCodes.Callvirt, _getTypeConverterDbValueToTypeValueMethod, null);
                            //emitter.CallVirtual(typeof(DatabaseTypeConverter).GetMethod(nameof(DatabaseTypeConverter.DbValueToTypeValue)));

                            il.Emit(OpCodes.Unbox_Any, trueType);
                            //emitter.UnboxAny(propertyDef.Type);

                            // stack is now [target][target][TypeValue]
                        }
                        else
                        {
                            //默认
                            // stack is now [target][target][value-as-object]


                            if (trueType.IsEnum)
                            {
                                // stack is now [target][target][value-as-object]
                                il.Emit(OpCodes.Castclass, typeof(string));
                                //emitter.CastClass<string>(); //stack is now [target][target][string]

                                il.Emit(OpCodes.Stloc, enumStringTempLocal);
                                //emitter.StoreLocal(enumStringTempLocal); //stack is now [target][target]

                                if (propertyDef.NullableUnderlyingType != null)
                                {
                                    il.Emit(OpCodes.Ldtoken, propertyDef.NullableUnderlyingType);
                                    //emitter.LoadConstant(propertyDef.NullableUnderlyingType);
                                }
                                else
                                {
                                    il.Emit(OpCodes.Ldtoken, propertyDef.Type);
                                    //emitter.LoadConstant(propertyDef.Type);//stack is now[target][target][propertyType-token]
                                }

                                il.EmitCall(OpCodes.Call, _getTypeFromHandleMethod, null);
                                //emitter.Call(typeof(Type).GetMethod(nameof(Type.GetTypeFromHandle)));//stack is now[target][target][propertyType]

                                il.Emit(OpCodes.Ldloc, enumStringTempLocal);
                                //emitter.LoadLocal(enumStringTempLocal);//stack is now[target][target][propertyType][string]

                                il.Emit(OpCodes.Ldc_I4_1);
                                //emitter.LoadConstant(true);//stack is now[target][target][propertyType][string][true]

                                il.EmitCall(OpCodes.Call, _enumParseMethod, null);
                                //emitter.Call(EnumParse);//stack is now[target][target][value]

                                if (propertyDef.NullableUnderlyingType != null)
                                {
                                    il.Emit(OpCodes.Unbox_Any, propertyDef.NullableUnderlyingType);
                                    //emitter.UnboxAny(propertyDef.NullableUnderlyingType);
                                }
                                else
                                {
                                    il.Emit(OpCodes.Unbox_Any, propertyDef.Type);
                                    //emitter.UnboxAny(propertyDef.Type);
                                }

                                //stack is now[target][target][typed-value]
                            }
                            else
                            {
                                // stack is now [target][target][value-as-object]

                                if (dbValueType == trueType)
                                {
                                    il.Emit(OpCodes.Unbox_Any, trueType);
                                }
                                else
                                {
                                    FlexibleConvertBoxedFromHeadOfStack(il, dbValueType, trueType);
                                }

                                //stack is now[target][target][typed-value]
                            }
                        }

                        if (propertyDef.NullableUnderlyingType != null)
                        {
                            il.Emit(OpCodes.Newobj, propertyDef.Type.GetConstructor(new Type[] { propertyDef.NullableUnderlyingType }) !);
                            //emitter.NewObject(propertyDef.Type.GetConstructor(new Type[] { propertyDef.NullableUnderlyingType }));
                        }
                    }

                    #endregion

                    //===赋值================================================================================
                    // stack is now [target][target][TypeValue]

                    if (propertyDef.Type.IsValueType)
                    {
                        il.EmitCall(OpCodes.Call, propertyDef.SetMethod, null);
                        //emitter.Call(GetPropertySetter(propertyDef.PropertyInfo, def.EntityType));
                    }
                    else
                    {
                        il.EmitCall(OpCodes.Callvirt, propertyDef.SetMethod, null);
                        //emitter.CallVirtual(GetPropertySetter(propertyDef.PropertyInfo, def.EntityType));
                    }

                    //stack is now[target]
                    il.Emit(OpCodes.Br_S, finishLable);
                    //emitter.Branch(finishLable);

                    il.MarkLabel(dbNullLabel);
                    //emitter.MarkLabel(dbNullLabel);

                    il.Emit(OpCodes.Pop);
                    il.Emit(OpCodes.Pop);
                    //emitter.Pop();
                    //emitter.Pop();
                    if (hasConverter)
                    {
                        il.Emit(OpCodes.Pop);
                    }

                    if (firstProperty && returnNullIfFirstNull)
                    {
                        il.Emit(OpCodes.Pop);
                        il.Emit(OpCodes.Ldnull); //stack is now [null]
                        il.Emit(OpCodes.Br, allFinished);
                    }

                    il.MarkLabel(finishLable);
                    //emitter.MarkLabel(finishLable);
                    firstProperty = false;
                }

                il.MarkLabel(allFinished);

                //emitter.StoreLocal(returnValueLocal);

                //emitter.LoadLocal(returnValueLocal);

                il.Emit(OpCodes.Ret);
                //emitter.Return();
            }
            catch (Exception ex)
            {
                //string info = ex.GetDebugInfo();
                throw Exceptions.MapperError(innerException: ex);
            }
        }