Dapper DynamicParameters.ParameterNames无法在foreach循环中迭代的问题
解决Dapper DynamicParameters参数日志记录问题
问题根源
用new DynamicParameters(匿名对象)初始化的参数,其ParameterNames集合仅包含手动通过Add方法添加的参数;通过对象模板初始化的参数会被存储在内部的templates集合中,不会被纳入ParameterNames,因此遍历该集合无法获取参数值。
更优解决方案:利用Dapper原生方法加载参数
无需反射,直接借助DynamicParameters实现的IDynamicParameters接口方法,将参数加载到临时DbCommand中,再从命令的参数集合提取信息:
private IEnumerable<SqlParameter> ConvertDynamicParameters(DynamicParameters dynamicParams) { using var cmd = new SqlCommand(); // 可根据数据库类型创建对应DbCommand dynamicParams.AddParameters(cmd, null); // 让Dapper自动将所有参数加载到命令中 foreach (SqlParameter param in cmd.Parameters) { yield return new SqlParameter(param.ParameterName, param.Value); } }
该方案依赖Dapper自身的参数映射逻辑,不会因内部字段变更失效,稳定性更高。
反射方案的可行性与实现
反射遍历templates的方案可行,但需注意Dapper版本迭代可能导致内部字段名变更,存在维护风险。以下是Dapper 2.x版本的示例实现:
private IEnumerable<(string Name, object Value)> ExtractTemplateParameters(DynamicParameters dynamicParams) { // 获取内部的_templates字段 var templatesField = typeof(DynamicParameters).GetField("_templates", BindingFlags.NonPublic | BindingFlags.Instance); if (templatesField == null) yield break; var templates = (IEnumerable)templatesField.GetValue(dynamicParams); foreach (var template in templates) { // 获取模板中存储的匿名对象 var valueProp = template.GetType().GetProperty("Value"); if (valueProp == null) continue; var paramObj = valueProp.GetValue(template); if (paramObj == null) continue; // 遍历匿名对象属性提取参数名和值 foreach (var prop in paramObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)) { yield return (prop.Name, prop.GetValue(paramObj)); } } }
若后续Dapper更新修改了内部字段名(比如_templates),需同步调整代码。
额外建议
如果需要记录最终执行的带参数SQL,可结合CommandDefinition和Dapper的参数替换逻辑生成日志字符串,但注意仅用于日志,不可直接执行(避免SQL注入风险)。
内容的提问来源于stack exchange,提问作者Shad
相关产品推荐
相关产品推荐

