指定了太多参数的过程或函数'xyz'



我知道这类问题在SO上至少被问了十几次,但我已经浏览了以前在这里能找到的所有问题和答案,但我发现没有一个适用。我在页面上使用了几个FormView对象,现在想添加编辑其中一个对象的选项。FormView由链接到存储过程的SqlDataSource填充,所以我制作了一个存储过程来更新记录,并将其添加到SqlDataSource中,现在看起来如下:

<asp:SqlDataSource ID="TestSqlDataSource" runat="server" 
                   SelectCommandType="StoredProcedure" 
                   ConnectionString="<%$ ConnectionStrings:development %>" 
                   SelectCommand="usp_GetNewTestDetails" 
                   UpdateCommand="usp_UpdateTest" 
                   UpdateCommandType="StoredProcedure" 
                   onupdating="TestSqlDataSource_Updating">
    <SelectParameters>
        <asp:SessionParameter SessionField="TestID" Name="TestID"/>
    </SelectParameters>
    <UpdateParameters>
        <asp:Parameter Name="testId" Type="Int32"/>
        <asp:Parameter Name="testerLicense" Type="Int32" />
        <asp:Parameter Name="premiseOwner" Type="String" />
        <asp:Parameter Name="premiseAddress" Type="String" />
        <asp:Parameter Name="premiseCity" Type="String" />
        <asp:Parameter Name="premiseState" Type="String" />
        <asp:Parameter Name="premiseZip" Type="String" />
        <asp:Parameter Name="protectionType" Type="String" />
        <asp:Parameter Name="testType" Type="String" />
        <asp:Parameter Name="repairs" Type="String" />
        <asp:Parameter Name="notes" Type="String" />
        <asp:Parameter Name="testDate" Type="DateTime" />
        <asp:Parameter Name="employerName" Type="String" />
        <asp:Parameter Name="employerAddress" Type="String" />
        <asp:Parameter Name="phoneNumber" Type="String" />
        <asp:Parameter Name="emailAddress" Type="String" />
        <asp:Parameter Name="dataEntryName" Type="String" />
        <asp:Parameter Name="dataEntryPhone" Type="String" />
        <asp:Parameter Name="signature" Type="String" />
        <asp:Parameter Name="entryDate" Type="DateTime" />
    </UpdateParameters>
</asp:SqlDataSource>

当我尝试更新记录时,我收到一个错误,说我的查询中有太多参数。我已经三次检查了代码中的参数(名称、编号甚至顺序)是否与存储过程中的参数完全匹配。

在试图寻找答案的过程中,我看到了这篇引用该网站的帖子(由于原文似乎已被删除,我不得不访问archive.org)。我应用了他们建议的向trace函数添加参数的方法。我发现,在我的存储过程中,有一些来自选择过程的"查找"值不在更新过程中。我试图更新的表只有测试人员的ID,但用户也想看到他们的名字,所以它引用了那个表,但在FormView中,这些字段在编辑模式下是只读的,所以他们不能尝试更改它。所有其他参数都排成一行。。。只有那些查找值是关闭的。

我认为,通过包括要传递的特定参数列表,它只会使用这些参数,但这似乎是不正确的。现在我被难住了,因为我已经指定了参数,而且在任何地方都看不到它们被select存储过程中的参数覆盖。我在哪里告诉它不要使用那些只读值?

我不想从原始存储过程中删除它们,因为用户需要它们。到目前为止,我想出的一个解决方法是将它们添加到存储过程中,然后永远不要使用它们。虽然我很确定这会起作用,但这在很大程度上只是掩盖了问题,而不是解决它


编辑:附加代码,根据请求

这是将参数输出到trace函数的方法:

protected void TestSqlDataSource_Updating(object sender, SqlDataSourceCommandEventArgs e)
{
    for (int i = 0; i < e.Command.Parameters.Count; i++)
    {
        Trace.Write(e.Command.Parameters[i].ParameterName);
        if (e.Command.Parameters[i].Value != null)
        {
            Trace.Write(e.Command.Parameters[i].Value.ToString());
        }
    }
}

这是用于更新的存储过程:

ALTER PROCEDURE [dbo].[usp_UpdateTest]
    @testId INT ,
    @testerLicense INT ,
    @premiseOwner VARCHAR(50) ,
    @premiseAddress VARCHAR(150) ,
    @premiseCity VARCHAR(50) ,
    @premiseState VARCHAR(2) ,
    @premiseZip VARCHAR(10) ,
    @protectionType VARCHAR(11) ,
    @testType VARCHAR(2) ,
    @repairs VARCHAR(200) ,
    @notes VARCHAR(300) ,
    @testDate DATETIME ,
    @employerName VARCHAR(50) ,
    @employerAddress VARCHAR(150) ,
    @phoneNumber VARCHAR(25) ,
    @emailAddress VARCHAR(60) ,
    @dataEntryName VARCHAR(50) ,
    @dataEntryPhone VARCHAR(25) ,
    @signature VARCHAR(50) ,
    @entryDate DATETIME
AS 
    BEGIN
        SET NOCOUNT ON;
        UPDATE  dbo.Tests
        SET     TesterLicense = @testerLicense ,
                PremiseOwner = @premiseOwner ,
                PremiseAddress = @premiseAddress ,
                PremiseCity = @premiseCity ,
                PremiseState = @premiseState ,
                PremiseZip = @premiseZip ,
                ProtectionType = @protectionType ,
                TestType = @testType ,
                Repairs = @repairs ,
                Notes = @notes ,
                TestDate = @testDate ,
                EmployerName = @employerName ,
                EmployerAddress = @employerAddress ,
                PhoneNumber = @phoneNumber ,
                EmailAddress = @emailAddress ,
                DataEntryName = @dataEntryName ,
                DataEntryPhone = @dataEntryPhone ,
                Signature = @signature ,
                EntryDate = @entryDate 
        WHERE TestID = @testId
    END

最终我自己解决了这个问题。这与Visual Studio根据存储过程的模式为我创建模板有关。当模板自动生成时,<EditItemTemplate>部分中的每个文本框都会生成如下:

<asp:TextBox ID="TestIDTextBox" runat="server" Text='<%# Bind("TestID") %>'/>

事实证明是Bind语句导致了这种情况。VS自动为使用Bind填充的任何字段创建一个参数。尽管我认为<UpdateParameters>部分应该覆盖这一点,但事实恰恰相反。我能够通过将这些字段上的代码从Bind更改为Eval:来防止这些只读字段传递回它们的参数

<asp:TextBox ID="TestIDTextBox" runat="server" Text='<%# Eval("TestID") %>'/>

现在效果很好。


附录:

发现这在另一个方向上也会导致同样的问题。如果将不希望编辑的字段标记为Eval,但需要将其包含在更新中(例如行ID),则该字段将不起作用,这一次参数太少。我现在想知道<UpdateParameters>部分的目的是什么,因为它似乎没有遵循其中的任何内容。。。

您可以在例如OnDelete事件(e.Command.parameters.RemoveAt(i))期间删除不需要的参数。

最新更新