将数据 Table 传递给 Table - 存储过程中的值参数不起作用

Passing DataTable to Table-Valued Parameter in stored procedure not working

因此,我需要将 table 值参数(从 CheckBoxLists 中的选定选项填充)传递给存储过程,以便检索符合我 table 中某些条件的食谱-valued 参数,但是当我尝试这样做时,它没有 return 任何东西。我正在研究 ASP.Net 和 C#。

SQL 服务器存储过程

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 正在正确接收和存储在复选框列表中选择的选项。

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

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;
}

感谢您的帮助!

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

的 table 类型
CREATE TYPE dbo.Filters AS TABLE

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

的 table 变量
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 条件的含义,这可能会或可能不会影响您的情况.

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

但是,当用户单击搜索按钮时,会将他重定向到另一个页面。在这个显示搜索结果的页面中,我调用了根据选定的复选框列表选项填充我的 DataTable 的方法。但是由于我将他重定向到另一个页面,回发使我的带有复选框列表值的 DataTable 完全无用。

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