将DataTable传递给存储过程中的表值参数不起作用[关闭]

Posted

技术标签:

【中文标题】将DataTable传递给存储过程中的表值参数不起作用[关闭]【英文标题】:Passing DataTable to Table-Valued Parameter in stored procedure not working [closed] 【发布时间】:2021-08-23 12:44:29 【问题描述】:

因此,我需要将表值参数(从 CheckBoxLists 中的选定选项填充)传递给存储过程,以便检索与我的表值参数中的某些条件匹配的配方,但是当我尝试这样做时它,它不返回任何东西。我正在研究 ASP.Net 和 C#。

SQL Server 存储过程

CREATE TYPE dbo.Filtros AS TABLE
(
    Categoria NVARCHAR(50),
    Dificuldade NVARCHAR(50),
    Duracao NVARCHAR(50)
);
GO

ALTER PROCEDURE [dbo].[uspPesquisarReceita] (@TVP dbo.Filtros READONLY)
AS
BEGIN
    SELECT R.NomeReceita, C.NomeCategoria, DF.Dificuldade, D.Duracao, R.ClassificacaoGeral, R.DataPublicacao, R.Foto, R.NumVisualizacoes, R.IDReceita
        FROM dbo.Receitas R 
        LEFT JOIN dbo.Categorias C ON R.IDCategoria = C.IDCategoria
        LEFT JOIN dbo.Dificuldade DF ON R.IDDificuldade = DF.IDDificuldade
        LEFT JOIN dbo.Duracao D ON R.IDDuracao = D.IDDuracao
        WHERE R.IDEstado = 1 AND C.NomeCategoria IN (SELECT Categoria FROM @TVP) OR DF.Dificuldade IN (SELECT Dificuldade FROM @TVP) OR D.Duracao IN (SELECT Duracao FROM @TVP)
END

我用来填充用作 TVP 的 DataTable 的代码是正确的,因为我通过将其内容打印到标签来测试它。因此,DataTable 正在正确接收和存储复选框列表中选择的选项。

用于存储过程和 DataTable 的 C# 用于存储来自存储过程的结果数据

public SqlDataReader receitaPesquisada(DataConnection conn, string pesquisa, DataTable tabelaParam)

    SqlDataReader drObterReceita = null;

    try
    
        string strCmmd = "uspPesquisarReceita";
        SqlCommand command = new SqlCommand(strCmmd, conn.Connection);
        command.CommandType = CommandType.StoredProcedure;
        command.Parameters.Add("@Pesquisa", SqlDbType.NVarChar).Value = pesquisa;
        SqlParameter param = new SqlParameter("@TVP", tabelaParam);
        param.SqlDbType = SqlDbType.Structured;
        param.TypeName = "dbo.Filtros";
        command.Parameters.Add(param);


        drObterReceita = command.ExecuteReader();

        return drObterReceita;

    
    catch (Exception ex)
    
        Console.Write("Algo correu mal no método" + ex.ToString());

        return drObterReceita;
    


public DataTable imprimirReceitaPesquisada(string pesquisa, DataTable tabelaParam)

    DataConnection conn = new DataConnection();

    DataTable dtbReceitaPesquisada = new DataTable();

    dtbReceitaPesquisada.Columns.Add("NomeReceita", typeof(string));
    dtbReceitaPesquisada.Columns.Add("Categoria", typeof(string));
    dtbReceitaPesquisada.Columns.Add("Dificuldade", typeof(string));
    dtbReceitaPesquisada.Columns.Add("Duracao", typeof(string));
    dtbReceitaPesquisada.Columns.Add("ClassificacaoGeral", typeof(string));
    dtbReceitaPesquisada.Columns.Add("DataPublicacao", typeof(string));
    dtbReceitaPesquisada.Columns.Add("Foto", typeof(string));
    dtbReceitaPesquisada.Columns.Add("NumVisualizacoes", typeof(string));

    try
    
        conn.openConnection();

        SqlDataReader drObterReceita = this.receitaPesquisada(conn, pesquisa, tabelaParam);

        while (drObterReceita.Read())
        
            dtbReceitaPesquisada.Rows.Add(drObterReceita[0].ToString(), drObterReceita[1].ToString(), drObterReceita[2].ToString(), drObterReceita[3].ToString(), Math.Round(double.Parse(drObterReceita[4].ToString()), 1).ToString(), drObterReceita[5].ToString(), drObterReceita[6].ToString(), drObterReceita[7].ToString());
        
    
    catch (Exception ex)
    
        Console.Write("Algo correu mal no método" + ex.ToString());
    
    finally
    
        conn.closeConnection();
    
    return dtbReceitaPesquisada;

感谢您的帮助!

【问题讨论】:

您的代码会创建一个 nvarchar 参数并将其添加到命令中。您的 TVP 参数永远不会被添加或使用。 感谢 SMor 的输入!发现得好。但是,即使添加了参数,它仍然无法正常工作。该页面不显示任何内容。 Filtros != Filters param.Direction = ParameterDirection.Input; 你也应该用using来处理连接、命令和阅读器对象 你是对的@AlexanderPetrov。那是错误的,但在写这篇文章时确实是一个错字。类型表和类型名称具有相同的名称。不过谢谢! 【参考方案1】:

正如@Alexander Petrov 正确指出的那样,您正在声明一个名为 dbo.filters 的表类型

CREATE TYPE dbo.Filters AS TABLE

但在存储过程定义中,您传递的是 dbo.filtros 类型的表变量

ALTER PROCEDURE [dbo].[uspPesquisarReceita] (@TVP dbo.Filtros READONLY)

它应该是 dbo.filters 类型。

此外,在不带括号“ ( ) ”的 where 子句中同时使用 AND 和 OR 运算符时,请务必小心,因为 SQL 中 AND 优先于 OR,因此您的预期条件可能不会给您预期的结果。

让我解释一下,下面是你用过的地方

WHERE R.IDEstado = 1 AND C.NomeCategoria IN (SELECT Categoria FROM @TVP) OR DF.Dificuldade IN (SELECT Dificuldade FROM @TVP) OR D.Duracao IN (SELECT Duracao FROM @TVP)

如果您运行查询,您将在结果集中看到 R.IDEstado = 1 和 C.NomeCategoria 的值来自 @TVP 中的 Categoria 列的值,这两个都必须为真。 评估此 AND 后,将评估其他 OR 条件。

但是,您可能希望您的结果符合第一个条件

R.IDEstado = 1 

强制为真,并且任何一个或多个条件来自

C.NomeCategoria IN (SELECT Categoria FROM @TVP) OR DF.Dificuldade IN (SELECT Dificuldade FROM @TVP) OR D.Duracao IN (SELECT Duracao FROM @TVP)

应该是正确的,但是如上所述,您并没有从您的查询中清楚地得到它。

所以你应该使用下面的 where,括号中的所有 OR 条件:

WHERE R.IDEstado = 1 AND (C.NomeCategoria IN (SELECT Categoria FROM @TVP) OR DF.Dificuldade IN (SELECT Dificuldade FROM @TVP) OR D.Duracao IN (SELECT Duracao FROM @TVP))

注意:您可能在查询中使用了 AND 和 OR 条件作为缩进,我只是在解释在 where 子句中使用 AND 和 OR 条件而不带括号的含义,这可能会或可能不会影响您的情况。

【讨论】:

嗨@PankajSanwal!谢谢你的长帖。事实上,在我写这篇文章时,Filtros vs dbo.Filters 是我的一个错字。这两个有相同的名字。我已经在 SQL 中尝试过你的建议,这实际上很有意义,这正是我想要的,但我仍然没有得到任何结果。还有其他想法吗?【参考方案2】:

更新:我解决了我的问题。问题是我在用户单击搜索按钮后从复选框中检索值并将它们放入 DataTable 中。

但是,当用户单击搜索按钮时,它会将他重定向到不同的页面。在显示搜索结果的此页面中,我正在调用根据所选复选框列表选项填充我的 DataTable 的方法。但由于我将他重定向到不同的页面,回发使我的 DataTable 与 checkboxlist 值完全无用。

相反,我将 DataTable 分配给 Session 变量,并在重定向后在新页面中调用它。像魅力一样工作!谢谢大家。

【讨论】:

以上是关于将DataTable传递给存储过程中的表值参数不起作用[关闭]的主要内容,如果未能解决你的问题,请参考以下文章

使用ado.net将多个SQL表值参数传递到单个存储过程

如何给SQLSERVER存储过程传递数组参数

如何使用 JDBC 将表值参数(类数组参数)传递给 Microsoft SQL Server 2008 R2 中的存储过程? [复制]

表值参数

从表值参数将数据插入表中

如何从.net代码将表值参数传递给存储过程