Example #1
0
        private StatementAttribute PreStatement(MethodInfo methodInfo, Type returnType, bool isTaskReturnType)
        {
            returnType = isTaskReturnType ? returnType.GetGenericArguments().FirstOrDefault() : returnType;
            var statementAttr = methodInfo.GetCustomAttribute <StatementAttribute>();
            var methodName    = methodInfo.Name;

            if (isTaskReturnType && methodInfo.Name.EndsWith("Async"))
            {
                methodName = methodName.Substring(0, methodName.Length - 5);
            }

            if (statementAttr != null)
            {
                statementAttr.Id = !String.IsNullOrEmpty(statementAttr.Id) ? statementAttr.Id
                    : methodName;
            }
            else
            {
                statementAttr = new StatementAttribute
                {
                    Id = methodName
                };
            }
            if (returnType == typeof(DataTable))
            {
                statementAttr.Execute = ExecuteBehavior.GetDataTable;
                return(statementAttr);
            }
            if (returnType == typeof(DataSet))
            {
                statementAttr.Execute = ExecuteBehavior.GetDataSet;
                return(statementAttr);
            }
            if (statementAttr.Execute == ExecuteBehavior.Auto)
            {
                if (returnType == typeof(int) || returnType == _voidType || returnType == null)
                {
                    statementAttr.Execute = ExecuteBehavior.Execute;
                }
                else if (returnType.IsValueType || returnType == typeof(string))
                {
                    statementAttr.Execute = ExecuteBehavior.ExecuteScalar;
                }
                else
                {
                    var isQueryEnumerable = typeof(IEnumerable).IsAssignableFrom(returnType);
                    if (isQueryEnumerable)
                    {
                        statementAttr.Execute = ExecuteBehavior.Query;
                    }
                    else
                    {
                        statementAttr.Execute = ExecuteBehavior.QuerySingle;
                    }
                }
            }
            return(statementAttr);
        }
Example #2
0
 private static void EmitSetDataSourceChoice(ILGenerator ilGen, StatementAttribute statementAttr)
 {
     if (statementAttr.SourceChoice != DataSourceChoice.Unknow)
     {
         ilGen.LoadLocalVar(0);
         ilGen.LoadInt32(statementAttr.SourceChoice.GetHashCode());
         ilGen.Callvirt(RequestContextType.Method.SetDataSourceChoice);
     }
 }
Example #3
0
 private static void EmitSetCommandType(ILGenerator ilGen, StatementAttribute statementAttr)
 {
     if (statementAttr.CommandType != CommandType.Text)
     {
         ilGen.LoadLocalVar(0);
         ilGen.LoadInt32(statementAttr.CommandType.GetHashCode());
         ilGen.Callvirt(RequestContextType.Method.SetCommandType);
     }
 }
Example #4
0
 private static void SetCmdTypeAndSourceChoice(StatementAttribute statementAttr, ILGenerator ilGenerator)
 {
     if (statementAttr.CommandType != CommandType.Text)
     {
         ilGenerator.Emit(OpCodes.Ldloc_0);
         EmitUtils.LoadInt32(ilGenerator, statementAttr.CommandType.GetHashCode());
         ilGenerator.Emit(OpCodes.Call, _set_CommandTypeMethod);
     }
     if (statementAttr.SourceChoice != DataSourceChoice.Unknow)
     {
         ilGenerator.Emit(OpCodes.Ldloc_0);
         EmitUtils.LoadInt32(ilGenerator, statementAttr.SourceChoice.GetHashCode());
         ilGenerator.Emit(OpCodes.Call, _set_DataSourceChoiceMethod);
     }
 }
Example #5
0
        private MethodInfo PreExecuteMethod(StatementAttribute statementAttr, Type returnType, bool isTaskReturnType)
        {
            MethodInfo executeMethod;

            if (isTaskReturnType)
            {
                var realReturnType = returnType.GenericTypeArguments.FirstOrDefault();
                switch (statementAttr.Execute)
                {
                case ExecuteBehavior.Execute:
                {
                    executeMethod = typeof(ISmartSqlMapperAsync).GetMethod("ExecuteAsync", new Type[] { typeof(RequestContext) });
                    break;
                }

                case ExecuteBehavior.ExecuteScalar:
                {
                    var method = typeof(ISmartSqlMapperAsync).GetMethod("ExecuteScalarAsync", new Type[] { typeof(RequestContext) });

                    executeMethod = method.MakeGenericMethod(realReturnType);
                    break;
                }

                case ExecuteBehavior.QuerySingle:
                {
                    var method = typeof(ISmartSqlMapperAsync).GetMethod("QuerySingleAsync", new Type[] { typeof(RequestContext) });
                    executeMethod = method.MakeGenericMethod(realReturnType);
                    break;
                }

                case ExecuteBehavior.Query:
                {
                    var method         = typeof(ISmartSqlMapperAsync).GetMethod("QueryAsync", new Type[] { typeof(RequestContext) });
                    var enumerableType = realReturnType.GenericTypeArguments[0];
                    executeMethod = method.MakeGenericMethod(enumerableType);
                    break;
                }

                case ExecuteBehavior.GetDataTable:
                {
                    executeMethod = typeof(ISmartSqlMapperAsync).GetMethod("GetDataTableAsync", new Type[] { typeof(RequestContext) });
                    break;
                }

                case ExecuteBehavior.GetDataSet:
                {
                    executeMethod = typeof(ISmartSqlMapperAsync).GetMethod("GetDataSetAsync", new Type[] { typeof(RequestContext) });
                    break;
                }

                case ExecuteBehavior.FillMultiple:
                {
                    executeMethod = typeof(ISmartSqlMapperAsync).GetMethod("FillMultipleAsync", new Type[] { typeof(RequestContext), typeof(IMultipleResult) });
                    break;
                }

                case ExecuteBehavior.GetNested:
                {
                    var method = typeof(ISmartSqlMapperAsync).GetMethod("GetNestedAsync", new Type[] { typeof(RequestContext) });
                    executeMethod = method.MakeGenericMethod(realReturnType);
                    break;
                }

                default: { throw new ArgumentException(); }
                }
            }
            else
            {
                switch (statementAttr.Execute)
                {
                case ExecuteBehavior.Execute:
                {
                    executeMethod = typeof(ISmartSqlMapper).GetMethod("Execute", new Type[] { typeof(RequestContext) });
                    break;
                }

                case ExecuteBehavior.ExecuteScalar:
                {
                    var method = typeof(ISmartSqlMapper).GetMethod("ExecuteScalar", new Type[] { typeof(RequestContext) });
                    executeMethod = method.MakeGenericMethod(returnType);
                    break;
                }

                case ExecuteBehavior.QuerySingle:
                {
                    var method = typeof(ISmartSqlMapper).GetMethod("QuerySingle", new Type[] { typeof(RequestContext) });
                    executeMethod = method.MakeGenericMethod(returnType);
                    break;
                }

                case ExecuteBehavior.Query:
                {
                    var method         = typeof(ISmartSqlMapper).GetMethod("Query", new Type[] { typeof(RequestContext) });
                    var enumerableType = returnType.GenericTypeArguments[0];
                    executeMethod = method.MakeGenericMethod(new Type[] { enumerableType });
                    break;
                }

                case ExecuteBehavior.GetDataTable:
                {
                    executeMethod = typeof(ISmartSqlMapper).GetMethod("GetDataTable", new Type[] { typeof(RequestContext) });
                    break;
                }

                case ExecuteBehavior.GetDataSet:
                {
                    executeMethod = typeof(ISmartSqlMapper).GetMethod("GetDataSet", new Type[] { typeof(RequestContext) });
                    break;
                }

                case ExecuteBehavior.FillMultiple:
                {
                    executeMethod = typeof(ISmartSqlMapper).GetMethod("FillMultiple", new Type[] { typeof(RequestContext), typeof(IMultipleResult) });
                    break;
                }

                case ExecuteBehavior.GetNested:
                {
                    var method = typeof(ISmartSqlMapper).GetMethod("GetNested", new Type[] { typeof(RequestContext) });
                    executeMethod = method.MakeGenericMethod(returnType);
                    break;
                }

                default: { throw new ArgumentException(); }
                }
            }

            return(executeMethod);
        }
Example #6
0
        private StatementAttribute PreStatement(Type interfaceType, string scope, MethodInfo methodInfo, Type returnType, bool isTaskReturnType, ISmartSqlMapper smartSqlMapper)
        {
            returnType = isTaskReturnType ? returnType.GetGenericArguments().FirstOrDefault() : returnType;
            var statementAttr = methodInfo.GetCustomAttribute <StatementAttribute>();

            var methodName = _sqlIdNamingConvert == null ? methodInfo.Name : _sqlIdNamingConvert.Invoke(interfaceType, methodInfo);

            if (isTaskReturnType && methodInfo.Name.EndsWith("Async") && _sqlIdNamingConvert == null)
            {
                methodName = methodName.Substring(0, methodName.Length - 5);
            }
            if (statementAttr != null)
            {
                statementAttr.Id    = !String.IsNullOrEmpty(statementAttr.Id) ? statementAttr.Id : methodName;
                statementAttr.Scope = !String.IsNullOrEmpty(statementAttr.Scope) ? statementAttr.Scope : scope;
            }
            else
            {
                statementAttr = new StatementAttribute
                {
                    Scope = scope,
                    Id    = methodName
                };
            }

            if (returnType == typeof(DataTable))
            {
                statementAttr.Execute = ExecuteBehavior.GetDataTable;
                return(statementAttr);
            }
            if (returnType == typeof(DataSet))
            {
                statementAttr.Execute = ExecuteBehavior.GetDataSet;
                return(statementAttr);
            }
            if (IsValueTuple(returnType))
            {
                statementAttr.Execute = ExecuteBehavior.FillMultiple;
                return(statementAttr);
            }

            if (statementAttr.Execute == ExecuteBehavior.Auto)
            {
                SqlCommandType cmdType = SqlCommandType.Unknown;
                if (String.IsNullOrEmpty(statementAttr.Sql))
                {
                    var sqlStatement = smartSqlMapper.SmartSqlOptions.SmartSqlContext.GetStatement($"{statementAttr.Scope}.{statementAttr.Id}");
                    cmdType = sqlStatement.SqlCommandType;
                    if (sqlStatement.MultipleResultMap != null && !returnType.IsValueType)
                    {
                        statementAttr.Execute = ExecuteBehavior.GetNested;
                        return(statementAttr);
                    }
                }
                else
                {
                    cmdType = _commandAnalyzer.Analyse(statementAttr.Sql);
                }

                if (returnType == typeof(int) || returnType == _voidType || returnType == null)
                {
                    statementAttr.Execute = ExecuteBehavior.Execute;
                    if (returnType == typeof(int))
                    {
                        if (cmdType.HasFlag(SqlCommandType.Select))
                        {
                            statementAttr.Execute = ExecuteBehavior.ExecuteScalar;
                        }
                    }
                }
                else if (returnType.IsValueType || returnType == typeof(string))
                {
                    statementAttr.Execute = ExecuteBehavior.ExecuteScalar;
                    if (!cmdType.HasFlag(SqlCommandType.Select))
                    {
                        statementAttr.Execute = ExecuteBehavior.Execute;
                    }
                }
                else
                {
                    var isQueryEnumerable = typeof(IEnumerable).IsAssignableFrom(returnType);
                    if (isQueryEnumerable)
                    {
                        statementAttr.Execute = ExecuteBehavior.Query;
                    }
                    else
                    {
                        statementAttr.Execute = ExecuteBehavior.QuerySingle;
                    }
                }
            }
            return(statementAttr);
        }
Example #7
0
 private void EmitSetSqlId(ILGenerator ilGenerator, StatementAttribute statementAttr)
 {
     ilGenerator.Emit(OpCodes.Ldloc_0);
     ilGenerator.Emit(OpCodes.Ldstr, statementAttr.Id);
     ilGenerator.Emit(OpCodes.Call, _set_SqlIdMethod);
 }
Example #8
0
 private void EmitSetRealSql(ILGenerator ilGenerator, StatementAttribute statementAttr)
 {
     ilGenerator.Emit(OpCodes.Ldloc_0);
     ilGenerator.Emit(OpCodes.Ldstr, statementAttr.Sql);
     ilGenerator.Emit(OpCodes.Call, _set_RealSqlMethod);
 }
Example #9
0
        private void BuildMethod(Type interfaceType, TypeBuilder typeBuilder, MethodInfo methodInfo, FieldBuilder sqlMapperField, ISmartSqlMapper smartSqlMapper, string scope)
        {
            var methodParams = methodInfo.GetParameters();
            var paramTypes   = methodParams.Select(m => m.ParameterType).ToArray();

            if (paramTypes.Any(p => p.IsGenericParameter))
            {
                _logger.LogError("SmartSql.DyRepository method parameters do not support generic parameters for the time being!");
                throw new SmartSqlException("SmartSql.DyRepository method parameters do not support generic parameters for the time being!");
            }
            var returnType = methodInfo.ReturnType;

            var implMehtod = typeBuilder.DefineMethod(methodInfo.Name
                                                      , MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final
                                                      , returnType, paramTypes);

            var isTaskReturnType = _taskType.IsAssignableFrom(returnType);

            if (methodInfo.IsGenericMethod)
            {
                var genericArgs       = methodInfo.GetGenericArguments();
                var gArgNames         = genericArgs.Select(gArg => gArg.Name).ToArray();
                var defineGenericArgs = implMehtod.DefineGenericParameters(gArgNames);
                for (int i = 0; i < gArgNames.Length; i++)
                {
                    var genericArg       = genericArgs[i];
                    var defineGenericArg = defineGenericArgs[i];
                    defineGenericArg.SetGenericParameterAttributes(genericArg.GenericParameterAttributes);
                }
            }

            StatementAttribute statementAttr = PreStatement(interfaceType, scope, methodInfo, returnType, isTaskReturnType, smartSqlMapper);
            var ilGenerator = implMehtod.GetILGenerator();

            ilGenerator.DeclareLocal(_reqContextType);
            ilGenerator.DeclareLocal(_dbParametersType);
            if (statementAttr.Execute == ExecuteBehavior.FillMultiple)
            {
                ilGenerator.DeclareLocal(_multipleResultType);
                ilGenerator.Emit(OpCodes.Newobj, _multipleResultImplCtor);
                ilGenerator.Emit(OpCodes.Stloc_2);
            }
            if (paramTypes.Length == 1 && paramTypes.First() == _reqContextType)
            {
                ilGenerator.Emit(OpCodes.Ldarg_1);
                ilGenerator.Emit(OpCodes.Stloc_0);
            }
            else
            {
                EmitNewRequestContext(ilGenerator);
                SetCmdTypeAndSourceChoice(statementAttr, ilGenerator);

                if (String.IsNullOrEmpty(statementAttr.Sql))
                {
                    EmitSetScope(ilGenerator, statementAttr.Scope);
                    EmitSetSqlId(ilGenerator, statementAttr);
                }
                else
                {
                    EmitSetRealSql(ilGenerator, statementAttr);
                }
                if (paramTypes.Length == 1 && !IsSimpleParam(paramTypes.First()))
                {
                    ilGenerator.Emit(OpCodes.Ldloc_0);
                    ilGenerator.Emit(OpCodes.Ldarg_1);
                    ilGenerator.Emit(OpCodes.Call, _set_RequestMethod);
                }
                else if (paramTypes.Length > 0)
                {
                    bool ignoreParameterCase = smartSqlMapper.SmartSqlOptions.SmartSqlContext.IgnoreParameterCase;
                    ilGenerator.Emit(ignoreParameterCase ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
                    ilGenerator.Emit(OpCodes.Newobj, _dbParametersCtor);
                    ilGenerator.Emit(OpCodes.Stloc_1);
                    for (int i = 0; i < methodParams.Length; i++)
                    {
                        int    argIndex     = i + 1;
                        var    reqParam     = methodParams[i];
                        string reqParamName = reqParam.Name;
                        var    paramAttr    = reqParam.GetCustomAttribute <ParamAttribute>();
                        if (paramAttr != null && !String.IsNullOrEmpty(paramAttr.Name))
                        {
                            reqParamName = paramAttr.Name;
                        }
                        ilGenerator.Emit(OpCodes.Ldloc_1);             //[dic]
                        ilGenerator.Emit(OpCodes.Ldstr, reqParamName); //[dic][param-name]
                        EmitUtils.LoadArg(ilGenerator, argIndex);
                        if (reqParam.ParameterType.IsValueType)
                        {
                            ilGenerator.Emit(OpCodes.Box, reqParam.ParameterType);
                        }
                        ilGenerator.Emit(OpCodes.Call, _addDbParamMehtod);//[empty]
                    }
                    ilGenerator.Emit(OpCodes.Ldloc_0);
                    ilGenerator.Emit(OpCodes.Ldloc_1);
                    ilGenerator.Emit(OpCodes.Call, _set_RequestMethod);
                }
            }

            MethodInfo executeMethod = null;

            executeMethod = PreExecuteMethod(statementAttr, returnType, isTaskReturnType);
            ilGenerator.Emit(OpCodes.Ldarg_0);               // [this]
            ilGenerator.Emit(OpCodes.Ldfld, sqlMapperField); //[this][sqlMapper]
            ilGenerator.Emit(OpCodes.Ldloc_0);               //[sqlMapper][requestContext]
            if (statementAttr.Execute == ExecuteBehavior.FillMultiple)
            {
                var returnGenericTypeArguments = returnType.GenericTypeArguments;
                foreach (var typeArg in returnGenericTypeArguments)
                {
                    bool isEnum           = _enumerableType.IsAssignableFrom(typeArg);
                    var  addTypeMapMethod = isEnum ? _multipleResult_AddTypeMap : _multipleResult_AddSingleTypeMap;
                    var  realRetType      = isEnum ? typeArg.GenericTypeArguments[0] : typeArg;
                    addTypeMapMethod = addTypeMapMethod.MakeGenericMethod(realRetType);
                    ilGenerator.Emit(OpCodes.Ldloc_2);
                    ilGenerator.Emit(OpCodes.Call, addTypeMapMethod);
                    ilGenerator.Emit(OpCodes.Pop);
                }
                ilGenerator.Emit(OpCodes.Ldloc_2);
            }
            ilGenerator.Emit(OpCodes.Call, executeMethod);
            if (returnType == _voidType)
            {
                ilGenerator.Emit(OpCodes.Pop);
            }
            if (statementAttr.Execute == ExecuteBehavior.FillMultiple)
            {
                ilGenerator.Emit(OpCodes.Pop);
                QueryMultipleToValueTuple(methodInfo, returnType, ilGenerator);
            }
            ilGenerator.Emit(OpCodes.Ret);

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug($"RepositoryBuilder.BuildMethod:{methodInfo.Name}->Statement:[Scope:{statementAttr.Scope},Id:{statementAttr.Id},Execute:{statementAttr.Execute},Sql:{statementAttr.Sql},IsAsync:{isTaskReturnType}]");
            }
        }
Example #10
0
        private void BuildMethod(TypeBuilder typeBuilder, MethodInfo methodInfo, FieldBuilder sqlMapperField, string scope)
        {
            var methodParams = methodInfo.GetParameters();
            var paramTypes   = methodParams.Select(m => m.ParameterType).ToArray();

            if (paramTypes.Any(p => p.IsGenericParameter))
            {
                _logger.LogError("SmartSql.DyRepository method parameters do not support generic parameters for the time being!");
                throw new SmartSqlException("SmartSql.DyRepository method parameters do not support generic parameters for the time being!");
            }
            var returnType = methodInfo.ReturnType;

            var implMehtod = typeBuilder.DefineMethod(methodInfo.Name
                                                      , MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final
                                                      , returnType, paramTypes);

            var isTaskReturnType = _taskType.IsAssignableFrom(returnType);

            if (methodInfo.IsGenericMethod)
            {
                var genericArgs       = methodInfo.GetGenericArguments();
                var gArgNames         = genericArgs.Select(gArg => gArg.Name).ToArray();
                var defineGenericArgs = implMehtod.DefineGenericParameters(gArgNames);
                for (int i = 0; i < gArgNames.Length; i++)
                {
                    var genericArg       = genericArgs[i];
                    var defineGenericArg = defineGenericArgs[i];
                    defineGenericArg.SetGenericParameterAttributes(genericArg.GenericParameterAttributes);
                }
            }

            StatementAttribute statementAttr = PreStatement(methodInfo, returnType, isTaskReturnType);
            var ilGenerator = implMehtod.GetILGenerator();

            ilGenerator.DeclareLocal(_reqContextType);
            ilGenerator.DeclareLocal(_reqParamsDicType);

            if (paramTypes.Length == 1 && paramTypes.First() == _reqContextType)
            {
                ilGenerator.Emit(OpCodes.Ldarg_1);
                ilGenerator.Emit(OpCodes.Stloc_0);
            }
            else
            {
                EmitNewRequestContext(ilGenerator);
                if (String.IsNullOrEmpty(statementAttr.Sql))
                {
                    EmitSetScope(ilGenerator, scope);
                    EmitSetSqlId(ilGenerator, statementAttr);
                }
                else
                {
                    EmitSetRealSql(ilGenerator, statementAttr);
                }
                if (paramTypes.Length == 1 && !IsSimpleParam(paramTypes.First()))
                {
                    ilGenerator.Emit(OpCodes.Ldloc_0);
                    ilGenerator.Emit(OpCodes.Ldarg_1);
                    ilGenerator.Emit(OpCodes.Call, _set_RequestMethod);
                }
                else if (paramTypes.Length > 0)
                {
                    ilGenerator.Emit(OpCodes.Newobj, _reqParamsDicCtor);
                    ilGenerator.Emit(OpCodes.Stloc_1);
                    for (int i = 0; i < methodParams.Length; i++)
                    {
                        int argIndex = i + 1;
                        var reqParam = methodParams[i];
                        if (reqParam.ParameterType == typeof(DataSourceChoice))
                        {
                            ilGenerator.Emit(OpCodes.Ldloc_0);
                            EmitUtils.LoadArg(ilGenerator, argIndex);
                            ilGenerator.Emit(OpCodes.Call, _set_DataSourceChoiceMethod);
                            continue;
                        }
                        if (reqParam.ParameterType == typeof(CommandType))
                        {
                            ilGenerator.Emit(OpCodes.Ldloc_0);
                            EmitUtils.LoadArg(ilGenerator, argIndex);
                            ilGenerator.Emit(OpCodes.Call, _set_CommandTypeMethod);
                            continue;
                        }
                        ilGenerator.Emit(OpCodes.Ldloc_1);              //[dic]
                        ilGenerator.Emit(OpCodes.Ldstr, reqParam.Name); //[dic][param-name]
                        EmitUtils.LoadArg(ilGenerator, argIndex);
                        if (reqParam.ParameterType.IsValueType)
                        {
                            ilGenerator.Emit(OpCodes.Box, reqParam.ParameterType);
                        }
                        ilGenerator.Emit(OpCodes.Call, _addReqParamMehtod);//[empty]
                    }
                    ilGenerator.Emit(OpCodes.Ldloc_0);
                    ilGenerator.Emit(OpCodes.Ldloc_1);
                    ilGenerator.Emit(OpCodes.Call, _set_RequestMethod);
                }
            }

            MethodInfo executeMethod = null;

            executeMethod = PreExecuteMethod(statementAttr, returnType, isTaskReturnType);
            ilGenerator.Emit(OpCodes.Ldarg_0);               // [this]
            ilGenerator.Emit(OpCodes.Ldfld, sqlMapperField); //[this][sqlMapper]
            ilGenerator.Emit(OpCodes.Ldloc_0);               //[sqlMapper][requestContext]
            ilGenerator.Emit(OpCodes.Call, executeMethod);
            if (returnType == _voidType)
            {
                ilGenerator.Emit(OpCodes.Pop);
            }
            ilGenerator.Emit(OpCodes.Ret);

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug($"RepositoryBuilder.BuildMethod:{methodInfo.Name}->Statement:[Scope:{scope},Id:{statementAttr.Id},Execute:{statementAttr.Execute},Sql:{statementAttr.Sql},IsAsync:{isTaskReturnType}]");
            }
        }
Example #11
0
        private void BuildMethod(Type interfaceType, TypeBuilder typeBuilder, MethodInfo methodInfo, FieldBuilder sqlMapperField, SmartSqlConfig smartSqlConfig, string scope)
        {
            var methodParams = methodInfo.GetParameters();
            var paramTypes   = methodParams.Select(m => m.ParameterType).ToArray();

            if (paramTypes.Any(p => p.IsGenericParameter))
            {
                _logger.LogError("SmartSql.DyRepository method parameters do not support generic parameters for the time being!");
                throw new SmartSqlException("SmartSql.DyRepository method parameters do not support generic parameters for the time being!");
            }
            var returnType = methodInfo.ReturnType;

            var implMethod = typeBuilder.DefineMethod(methodInfo.Name
                                                      , MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Virtual | MethodAttributes.Final
                                                      , returnType, paramTypes);

            var isTaskReturnType = CommonType.Task.IsAssignableFrom(returnType);

            if (methodInfo.IsGenericMethod)
            {
                var genericArgs       = methodInfo.GetGenericArguments();
                var gArgNames         = genericArgs.Select(gArg => gArg.Name).ToArray();
                var defineGenericArgs = implMethod.DefineGenericParameters(gArgNames);
                for (int i = 0; i < gArgNames.Length; i++)
                {
                    var genericArg       = genericArgs[i];
                    var defineGenericArg = defineGenericArgs[i];
                    defineGenericArg.SetGenericParameterAttributes(genericArg.GenericParameterAttributes);
                }
            }

            StatementAttribute statementAttr = PreStatement(interfaceType, scope, methodInfo, returnType, isTaskReturnType, smartSqlConfig);
            var  ilGen          = implMethod.GetILGenerator();
            bool onlyOneParam   = paramTypes.Length == 1;
            Type firstParamType = paramTypes.FirstOrDefault();

            ilGen.DeclareLocal(RequestContextType.AbstractType);

            if (onlyOneParam && RequestContextType.AbstractType.IsAssignableFrom(firstParamType))
            {
                throw new SmartSqlException($"DyRepository.Method ParameterType :{firstParamType.FullName} can not be RequestContext.");
                //ilGen.LoadArg(1);
                //ilGen.StoreLocalVar(0);
            }

            bool isOnlyOneClassParam = onlyOneParam && !IsSimpleParam(firstParamType);

            EmitNewRequestContext(ilGen, isOnlyOneClassParam, firstParamType);
            EmitSetCommandType(ilGen, statementAttr);
            EmitSetDataSourceChoice(ilGen, statementAttr);

            if (String.IsNullOrEmpty(statementAttr.Sql))
            {
                EmitSetScope(ilGen, statementAttr.Scope);
                EmitSetSqlId(ilGen, statementAttr);
            }
            else
            {
                EmitSetRealSql(ilGen, statementAttr);
            }
            if (isOnlyOneClassParam)
            {
                ilGen.LoadLocalVar(0);
                ilGen.LoadArg(1);
                ilGen.Callvirt(RequestContextType.Method.SetRequest);
            }
            else if (paramTypes.Length > 0)
            {
                ilGen.DeclareLocal(SqlParameterType.SqlParameterCollection);
                bool ignoreParameterCase = smartSqlConfig.Settings.IgnoreParameterCase;
                ilGen.Emit(ignoreParameterCase ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
                ilGen.New(SqlParameterType.Ctor.SqlParameterCollection);
                ilGen.StoreLocalVar(1);
                for (int i = 0; i < methodParams.Length; i++)
                {
                    int    argIndex     = i + 1;
                    var    reqParam     = methodParams[i];
                    string reqParamName = reqParam.Name;
                    var    paramAttr    = reqParam.GetCustomAttribute <ParamAttribute>();
                    if (paramAttr != null && !String.IsNullOrEmpty(paramAttr.Name))
                    {
                        reqParamName = paramAttr.Name;
                    }
                    ilGen.LoadLocalVar(1);
                    ilGen.LoadString(reqParamName);
                    ilGen.LoadArg(argIndex);

                    if (reqParam.ParameterType.IsValueType)
                    {
                        ilGen.Box(reqParam.ParameterType);
                    }
                    ilGen.LoadType(reqParam.ParameterType);
                    ilGen.New(SqlParameterType.Ctor.SqlParameter);
                    ilGen.Dup();
                    var getHandlerMethod = paramAttr?.FieldType != null?TypeHandlerCacheType.GetHandlerMethod(reqParam.ParameterType, paramAttr?.FieldType)
                                               : PropertyTypeHandlerCacheType.GetHandlerMethod(reqParam.ParameterType);

                    ilGen.Call(getHandlerMethod);
                    ilGen.Call(SqlParameterType.Method.SetTypeHandler);
                    ilGen.Call(SqlParameterType.Method.Add);
                }
                ilGen.LoadLocalVar(0);
                ilGen.LoadLocalVar(1);
                ilGen.Callvirt(RequestContextType.Method.SetRequest);
            }
            MethodInfo executeMethod = PreExecuteMethod(statementAttr, returnType, isTaskReturnType);

            ilGen.LoadArg(0);
            ilGen.FieldGet(sqlMapperField);
            ilGen.LoadLocalVar(0);
            ilGen.Call(executeMethod);
            if (returnType == CommonType.Void)
            {
                ilGen.Pop();
            }
            ilGen.Return();
            if (_logger.IsEnabled(LogLevel.Debug))
            {
                _logger.LogDebug($"RepositoryBuilder.BuildMethod:{methodInfo.Name}->Statement:[Scope:{statementAttr.Scope},Id:{statementAttr.Id},Execute:{statementAttr.Execute},Sql:{statementAttr.Sql},IsAsync:{isTaskReturnType}]");
            }
        }
Example #12
0
 private void EmitSetSqlId(ILGenerator ilGen, StatementAttribute statementAttr)
 {
     ilGen.LoadLocalVar(0);
     ilGen.LoadString(statementAttr.Id);
     ilGen.Callvirt(RequestContextType.Method.SetSqlId);
 }
Example #13
0
        private MethodInfo PreExecuteMethod(StatementAttribute statementAttr, Type returnType, bool isTaskReturnType)
        {
            MethodInfo executeMethod;

            if (isTaskReturnType)
            {
                var realReturnType = returnType.GenericTypeArguments.FirstOrDefault();
                switch (statementAttr.Execute)
                {
                case ExecuteBehavior.Execute:
                {
                    executeMethod = ISqlMapperType.Method.ExecuteAsync;
                    break;
                }

                case ExecuteBehavior.ExecuteScalar:
                {
                    executeMethod = ISqlMapperType.Method.ExecuteScalarAsync.MakeGenericMethod(realReturnType);
                    break;
                }

                case ExecuteBehavior.QuerySingle:
                {
                    executeMethod = ISqlMapperType.Method.QuerySingleAsync.MakeGenericMethod(realReturnType);
                    break;
                }

                case ExecuteBehavior.Query:
                {
                    var method         = ISqlMapperType.Method.QueryAsync;
                    var enumerableType = realReturnType.GenericTypeArguments[0];
                    executeMethod = method.MakeGenericMethod(enumerableType);
                    break;
                }

                case ExecuteBehavior.GetDataTable:
                {
                    executeMethod = ISqlMapperType.Method.GetDataTableAsync;
                    break;
                }

                case ExecuteBehavior.GetDataSet:
                {
                    executeMethod = ISqlMapperType.Method.GetDataSetAsync;
                    break;
                }

                default: { throw new ArgumentException(); }
                }
            }
            else
            {
                switch (statementAttr.Execute)
                {
                case ExecuteBehavior.Execute:
                {
                    executeMethod = ISqlMapperType.Method.Execute;
                    break;
                }

                case ExecuteBehavior.ExecuteScalar:
                {
                    executeMethod = ISqlMapperType.Method.ExecuteScalar.MakeGenericMethod(returnType);
                    break;
                }

                case ExecuteBehavior.QuerySingle:
                {
                    executeMethod = ISqlMapperType.Method.QuerySingle.MakeGenericMethod(returnType);
                    break;
                }

                case ExecuteBehavior.Query:
                {
                    var method         = ISqlMapperType.Method.Query;
                    var enumerableType = returnType.GenericTypeArguments[0];
                    executeMethod = method.MakeGenericMethod(new Type[] { enumerableType });
                    break;
                }

                case ExecuteBehavior.GetDataTable:
                {
                    executeMethod = ISqlMapperType.Method.GetDataTable;
                    break;
                }

                case ExecuteBehavior.GetDataSet:
                {
                    executeMethod = ISqlMapperType.Method.GetDataSet;
                    break;
                }

                default: { throw new ArgumentException(); }
                }
            }

            return(executeMethod);
        }
Example #14
0
        private StatementAttribute PreStatement(Type interfaceType, string scope, MethodInfo methodInfo, Type returnType, bool isTaskReturnType, SmartSqlConfig smartSqlConfig)
        {
            returnType = isTaskReturnType ? returnType.GetGenericArguments().FirstOrDefault() : returnType;
            var statementAttr = methodInfo.GetCustomAttribute <StatementAttribute>();

            var methodName = _sqlIdNamingConvert == null ? methodInfo.Name : _sqlIdNamingConvert.Invoke(interfaceType, methodInfo);

            if (isTaskReturnType && methodInfo.Name.EndsWith("Async") && _sqlIdNamingConvert == null)
            {
                methodName = methodName.Substring(0, methodName.Length - 5);
            }
            if (statementAttr != null)
            {
                statementAttr.Id    = !String.IsNullOrEmpty(statementAttr.Id) ? statementAttr.Id : methodName;
                statementAttr.Scope = !String.IsNullOrEmpty(statementAttr.Scope) ? statementAttr.Scope : scope;
            }
            else
            {
                statementAttr = new StatementAttribute
                {
                    Scope = scope,
                    Id    = methodName
                };
            }

            if (returnType == typeof(DataTable))
            {
                statementAttr.Execute = ExecuteBehavior.GetDataTable;
                return(statementAttr);
            }
            if (returnType == typeof(DataSet))
            {
                statementAttr.Execute = ExecuteBehavior.GetDataSet;
                return(statementAttr);
            }

            if (statementAttr.Execute == ExecuteBehavior.Auto)
            {
                Configuration.StatementType statementType = Configuration.StatementType.Unknown;
                if (String.IsNullOrEmpty(statementAttr.Sql))
                {
                    var sqlStatement = smartSqlConfig.GetSqlMap(statementAttr.Scope).GetStatement($"{statementAttr.Scope}.{statementAttr.Id}");
                    statementType = sqlStatement.StatementType;
                }
                else
                {
                    statementType = _statementAnalyzer.Analyse(statementAttr.Sql);
                }

                if (CommonType.IsValueTuple(returnType))
                {
                    statementAttr.Execute = ExecuteBehavior.QuerySingle;
                }
                else if (returnType == CommonType.Int32 || returnType == CommonType.Void || returnType == null)
                {
                    statementAttr.Execute = ExecuteBehavior.Execute;
                    if (returnType == CommonType.Int32)
                    {
                        if (statementType.HasFlag(Configuration.StatementType.Select))
                        {
                            statementAttr.Execute = ExecuteBehavior.ExecuteScalar;
                        }
                    }
                }
                else if (returnType.IsValueType || returnType == CommonType.String)
                {
                    statementAttr.Execute = ExecuteBehavior.ExecuteScalar;
                    if (!statementType.HasFlag(Configuration.StatementType.Select))
                    {
                        statementAttr.Execute = ExecuteBehavior.Execute;
                    }
                }
                else
                {
                    var isQueryEnumerable = typeof(IEnumerable).IsAssignableFrom(returnType);
                    statementAttr.Execute = isQueryEnumerable ? ExecuteBehavior.Query : ExecuteBehavior.QuerySingle;
                }
            }
            return(statementAttr);
        }
Example #15
0
        private Statement PreStatement(Type interfaceType, SqlMap sqlMap, MethodInfo methodInfo,
                                       Type returnType, bool isTaskReturnType, out ExecuteBehavior executeBehavior)
        {
            var statementAttr = methodInfo.GetCustomAttribute <StatementAttribute>();
            var methodName    = _sqlIdNamingConvert == null
                ? methodInfo.Name
                : _sqlIdNamingConvert.Invoke(interfaceType, methodInfo);

            if (isTaskReturnType && methodInfo.Name.EndsWith("Async") && _sqlIdNamingConvert == null)
            {
                methodName = methodName.Substring(0, methodName.Length - 5);
            }

            if (statementAttr != null)
            {
                statementAttr.Id = !String.IsNullOrEmpty(statementAttr.Id) ? statementAttr.Id : methodName;
            }
            else
            {
                statementAttr = new StatementAttribute
                {
                    Id = methodName
                };
            }

            var       fullSqlId = $"{sqlMap.Scope}.{statementAttr.Id}";
            Statement statement;

            if (String.IsNullOrEmpty(statementAttr.Sql))
            {
                statement = sqlMap.GetStatement(fullSqlId);
            }
            else
            {
                if (sqlMap.Statements.ContainsKey(fullSqlId))
                {
                    throw new SmartSqlException($"Statement.FullSqlId:[{fullSqlId}] already exists!");
                }

                var resultCacheAttr = methodInfo.GetCustomAttribute <ResultCacheAttribute>();
                statement = new Statement
                {
                    SqlMap        = sqlMap,
                    Id            = statementAttr.Id,
                    StatementType = _statementAnalyzer.Analyse(statementAttr.Sql),
                    SqlTags       = new List <ITag>
                    {
                        new SqlText(statementAttr.Sql, sqlMap.SmartSqlConfig.Database.DbProvider.ParameterPrefix)
                    },
                    CommandType = statementAttr.CommandType,
                    EnablePropertyChangedTrack = statementAttr.EnablePropertyChangedTrack,
                    ReadDb = statementAttr.ReadDb
                };
                if (statementAttr.CommandTimeout > 0)
                {
                    statement.CommandTimeout = statementAttr.CommandTimeout;
                }


                if (statementAttr.SourceChoice != DataSourceChoice.Unknow)
                {
                    statement.SourceChoice = statementAttr.SourceChoice;
                }

                if (resultCacheAttr != null)
                {
                    statement.CacheId = ParseCacheFullId(sqlMap.Scope, resultCacheAttr.CacheId);
                    statement.Cache   = sqlMap.GetCache(statement.CacheId);
                }

                sqlMap.Statements.Add(statement.FullSqlId, statement);
            }

            returnType = isTaskReturnType ? returnType.GetGenericArguments().FirstOrDefault() : returnType;
            if (returnType == typeof(DataTable))
            {
                statementAttr.Execute = ExecuteBehavior.GetDataTable;
            }

            if (returnType == typeof(DataSet))
            {
                statementAttr.Execute = ExecuteBehavior.GetDataSet;
            }

            if (statementAttr.Execute == ExecuteBehavior.Auto)
            {
                if (CommonType.IsValueTuple(returnType))
                {
                    statementAttr.Execute = ExecuteBehavior.QuerySingle;
                }
                else if (returnType == CommonType.Int32 || returnType == CommonType.Void || returnType == null)
                {
                    statementAttr.Execute = ExecuteBehavior.Execute;
                    if (returnType == CommonType.Int32)
                    {
                        if (statement.StatementType.HasFlag(Configuration.StatementType.Select))
                        {
                            statementAttr.Execute = ExecuteBehavior.ExecuteScalar;
                        }
                    }
                }
                else if (returnType.IsValueType || returnType == CommonType.String)
                {
                    statementAttr.Execute = ExecuteBehavior.ExecuteScalar;
                    if (!statement.StatementType.HasFlag(Configuration.StatementType.Select))
                    {
                        statementAttr.Execute = ExecuteBehavior.Execute;
                    }
                }
                else
                {
                    var isQueryEnumerable = typeof(IEnumerable).IsAssignableFrom(returnType);
                    statementAttr.Execute = isQueryEnumerable ? ExecuteBehavior.Query : ExecuteBehavior.QuerySingle;
                }
            }

            executeBehavior = statementAttr.Execute;
            return(statement);
        }