如何实现Dapper QueryMultipleAsync的泛型方法?当前实现报‘Parameter count mismatch.’错误
如何实现Dapper QueryMultipleAsync的泛型方法?当前实现报‘Parameter count mismatch.’错误
我帮你分析下这个问题哈,你遇到的「Parameter count mismatch.」错误,核心原因是通过反射调用Dapper的ReadAsync和ReadSingleAsync方法时,没有匹配到无参数的泛型重载版本,导致调用时参数不匹配。
错误根源
Dapper的SqlMapper.GridReader类中,ReadAsync和ReadSingleAsync都有多个重载(比如带CommandBehavior、commandTimeout参数的版本)。你当前的反射查找逻辑只过滤了方法名称和是否泛型,没限定参数数量,大概率拿到了带参数的重载,这时候用Invoke(multi, null)调用就会因为参数数量不符报错。
修正后的实现代码
下面是修复后的完整方法,我调整了反射查找方法的逻辑,同时加了方法缓存来提升性能:
// 缓存反射获取的方法,避免每次调用都重新查找 private static readonly MethodInfo _readAsyncGenericMethod = typeof(SqlMapper.GridReader) .GetMethods() .FirstOrDefault(m => m.Name == nameof(SqlMapper.GridReader.ReadAsync) && m.IsGenericMethod && m.GetParameters().Length == 0); private static readonly MethodInfo _readSingleAsyncGenericMethod = typeof(SqlMapper.GridReader) .GetMethods() .FirstOrDefault(m => m.Name == nameof(SqlMapper.GridReader.ReadSingleAsync) && m.IsGenericMethod && m.GetParameters().Length == 0); public async Task<List<object>> GetMultipleAsync<U>(string storedProcedure, U parameters, List<Type> types) { var result = new List<object>(); try { using (var multi = await _connection.QueryMultipleAsync(storedProcedure, parameters, commandType: CommandType.StoredProcedure, transaction: _transaction)) { foreach (var type in types) { if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(List<>)) { // 处理集合类型 var elementType = type.GetGenericArguments()[0]; var genericMethod = _readAsyncGenericMethod.MakeGenericMethod(elementType); var task = (Task)genericMethod.Invoke(multi, null); await task.ConfigureAwait(false); var data = task.GetType().GetProperty("Result")?.GetValue(task); if (data != null) { result.Add(data); } } else { // 处理单个对象类型 var genericMethod = _readSingleAsyncGenericMethod.MakeGenericMethod(type); var task = (Task)genericMethod.Invoke(multi, null); await task.ConfigureAwait(false); var data = task.GetType().GetProperty("Result")?.GetValue(task); if (data != null) { result.Add(data); } } } } } catch (Exception ex) { // 这里可以添加你的异常处理逻辑,比如日志记录 Console.WriteLine($"获取多数据集失败:{ex.Message}"); throw; // 建议不要吞掉异常,上层可以根据需要处理 } return result; }
关键优化点说明
精准匹配无参数重载
在查找ReadAsync和ReadSingleAsync方法时,增加了m.GetParameters().Length == 0的条件,确保拿到的是无参数的泛型重载,这样调用时传null就不会有参数不匹配的问题了。缓存反射方法
把反射获取到的方法实例缓存为静态字段,避免每次调用方法都重新遍历查找,大幅提升性能。空值安全处理
增加了?.空值判断,避免反射获取Result属性时出现空引用异常。
验证使用场景
你原来的调用方式完全可以正常工作:
var types = new List<Type> { typeof(List<ModelA>), typeof(List<ModelB>), typeof(long) }; var resultMultiple = await _dataAccess.GetMultipleAsync<DynamicParameters>(storedProcedure, parameters, types); // 解析结果 var ListA = resultMultiple[0] as List<ModelA>; var ListB = resultMultiple[1] as List<ModelB>; var val = (long)resultMultiple[2];
备注:内容来源于stack exchange,提问作者SYED NAWAZ PRINCE
相关产品推荐
相关产品推荐

