Dapper:过程或函数指定了太多参数

Posted

技术标签:

【中文标题】Dapper:过程或函数指定了太多参数【英文标题】:Dapper: Procedure or function has too many arguments specified 【发布时间】:2014-07-31 21:53:19 【问题描述】:

使用 Dapper 调用存储过程时,我收到以下错误:

Procedure or function has too many arguments specified

我正在使用 DynamicParameters 将简单参数列表添加到查询中。

参数代码如下:

var parameters = new DynamicParameters();
parameters.Add(p.Name, p.Value, direction: p.Mode);

查询代码如下:

var result = _connection.Query<T>(
            string.Format("0.1", request.SchemaName, request.StoredProcedureName),
            parameters,
            commandType: CommandType.StoredProcedure,
            transaction: _transaction);

profiler中执行的sql如下:

exec dbo.storedProcedureName @ParameterNames1=N'ParameterName',@ParameterNames2=N'ParameterName',@RemoveUnused=1

@ParameterNames1 根本不是参数的调用方式。实际上,名称是作为值 (N'ParameterName') 传入的。 @RemoveUnused 参数对我来说似乎完全是随机的,因为它根本不会出现在调用代码中。

可在此处找到完整代码:GitHub project 第 61 和 228 行。

编辑:我发现问题是由两次调用相同的过程引起的,但结果集不同。所以我第一次用 Query 调用它,第二次用 Query 调用它。为什么 Dapper 在这种情况下遇到问题仍然是个谜。

【问题讨论】:

您的代码似乎正确。所以现在正如错误所说,您已经传递了一些在您的 SP 中未定义的额外参数。因此,请检查您配置要传递的参数的代码。 @KrishnrajRana:感谢您的评论。据我所见,我没有传递额外的参数。由于我发现了一些额外的信息,所以我已经编辑了这个问题。 如果您的 SP 返回多个结果,那么您可以使用 QueryMultiple() 的 dapper。与其调用相同的 SP 两次,不如编写 SP 代码,使其在 sp 中执行第一个结果,然后将其用于第二个结果,然后根据您的要求返回这两个结果集。 【参考方案1】:

我最近遇到了这个问题,这似乎是由以下原因引起的:

您的存储过程可以返回多个数据集(可能基于 条件参数)。 您正在使用以下方法调用存储过程 Query&lt;T&gt;() 而不是 QueryMultiple() 然后映射数据集 通过Read&lt;T&gt;

我们最近从旧版本的 Dapper 升级到 v1.4 以支持表变量参数,并且我们开始遇到这种行为是升级的直接结果。

解决方案:

将基于Query&lt;T&gt; 的代码转换为QueryMultiple 实现。

【讨论】:

【参考方案2】:

我根本无法重现:

public void SO25069578_DynamicParams_Procs()

    var parameters = new DynamicParameters();
    parameters.Add("foo", "bar");
    try  connection.Execute("drop proc SO25069578");  catch  
    connection.Execute("create proc SO25069578 @foo nvarchar(max) as select @foo as [X]");
    var tran = connection.BeginTransaction(); // gist used transaction; behaves the same either way, though
    var row = connection.Query<HazX>("SO25069578", parameters,
        commandType: CommandType.StoredProcedure, transaction: tran).Single();
    tran.Rollback();
    row.X.IsEqualTo("bar");

public class HazX

    public string X  get; set; 

工作正常。 DynamicParameters 上有一个RemoveUnused 属性,位:使用动态参数时,不应该添加。我什至尝试过使用基于模板的构造函数:

parameters = new DynamicParameters(parameters);

但又一次:这很好用。是否有可能您使用的是 非常非常旧 版本的 dapper?你用的是什么版本?

【讨论】:

这似乎是一个非常具体的错误。我使用的是 NuGet 版本,它是 1.27,因为昨天发布了最新版本。我会深入研究一下,看看能不能找到解释。【参考方案3】:

我意识到这是一个旧线程。不过,我使用的是最新版本的 Nuget 包 (1.60.6),最近遇到了这个问题。

要重现这一点,您需要一个基于输入参数的存储过程,该过程可以返回 1 个或 2 个(超过 1 个)结果集。在代码中,我也使用 2 种不同的扩展方法来调用它(QueryMultipleAsync 将参数设置为 1 或 true,QueryAsync 将其设置为 0 或 false)。如果您的测试最终调用 SP 以首先返回多个结果集,则需要 1 个结果集的后续调用将失败并出现此错误。

我设法解决此问题的唯一方法是将 SP 分解为 2 个,以便它们具有不同的名称。

作为参考,我是这样称呼 SP 的:

var data = await sqlConnection.QueryAsync<T>(
             StoredProcedureName,
             parms,
             transaction: null,
             commandTimeout: null,
             commandType: CommandType.StoredProcedure)

var data = await sqlConnection.QueryMultipleAsync(
                        StoredProcedureName,
                        param: p,
                        commandType: CommandType.StoredProcedure)
                        .Map<Type1, Type2, long>
                        (
                            o1 => o1.Id,
                            o2 => o2.FkId ?? 0,
                            (o1, o2) =>  o1.Children = o2.ToList(); 
                        );

【讨论】:

【参考方案4】:

最近遇到了这个问题,原因是使用不同的 Dapper 方法两次调用相同的过程。 对同一 SQL 存储过程的第一次调用是通过 .QueryMultiple。使用 .QuerySingleOrDefault 再次使用参数调用相同的过程导致参数为原始问题中提到的 ParameterNames1 和 RemoveUnused。

【讨论】:

【参考方案5】:

这个 Dapper 问题是由在 QueryMultiple 之后读取数据集的 Read 方法引起的。 在这种情况下,Dapper 会缓存参数,如果您使用 Dapper Query 方法调用具有相同参数的相同存储过程,它将失败。 要解决此问题,请将 QueryMultiple 方法的调用从如下更改:

var reader = conn.QueryMultiple (spName, pars, commandType: CommandType.StoredProcedure);

到这里:

var cmd = new CommandDefinition (spName, pars, commandType: CommandType.StoredProcedure, flags: CommandFlags.NoCache);
var reader = conn.QueryMultiple (cmd);

【讨论】:

以上是关于Dapper:过程或函数指定了太多参数的主要内容,如果未能解决你的问题,请参考以下文章

存储过程指定了太多参数

将参数传递给C#中的存储过程

过程或函数指定的参数太多

您输入了太多参数 excel IF 错误

使用标量函数执行查询花费了太多时间

将多个参数传递给表值函数