Estoy tratando de pasar de una tabla de valor de parámetro a un procedimiento almacenado, pero sigo recibiendo una excepción (ver más abajo).

SqlCommand c = new SqlCommand("getPermittedUsers", myConn) { CommandType = CommandType.StoredProcedure };

c.Parameters.AddWithValue("@intNotifyingUserId", notifyingUserId);
c.Parameters.AddWithValue("@tSelectedPdfIds", sharedPdfs).SqlDbType = SqlDbType.Structured;

SqlDataReader dr = c.ExecuteReader();

El tipo está definido en el servidor como este:

CREATE TYPE [dbo].[IdList] AS TABLE(
    [Id] [int] NOT NULL
)

He intentado pasar sharedPdfs como un List<int>, y IQueryable<int>, pero seguir recibiendo la siguiente excepción:

Object must implement IConvertible.

Alguien sabe qué estoy haciendo mal? La documentación que se supone que yo debería ser capaz de pasar una lista como una TVP, pero no le da ningún ejemplo.

Gracias.

  • ¿Cómo se getPermittedUsers declarado?
  • Este es un long-shot, pero has probado a pasar una int[]?
  • Usted necesidad de utilizar DataTable.
  • Gracias, se trabajó con una DataTable. Molesto tener que convertir mi IQueryable < t > en un DataTable, aunque.
  • También se puede implementar la interfaz IEnumerable<SqlDataRecord>. lennilobel.wordpress.com/2009/07/29/…
InformationsquelleAutor nw. | 2011-08-08

2 Comentarios

  1. 16

    Puede pasar el parámetro como un DataTable, IEnumerable<SqlDataRecord>, o DbDataReader.

    • ? para el SQLCommand ¿estás seguro?
    • Sí, esos son los tipos de datos admitidos para una Tabla de Valor de Parámetro en SqlCommand. La documentación completa está aquí: msdn.microsoft.com/en-us/library/bb675163.aspx . Ver 1/3 de la manera abajo: «el Sistema.De datos.SqlClient apoya rellenar la tabla de parámetros con valores de tabla de datos, DbDataReader o Sistema.Las colecciones.Genérica.IEnumerable<SqlDataRecord> ([T:System.Collections.Generic.IEnumerable`1)] los objetos.»
    • es también posible en Oracle?
    • Parámetros con valores de tabla es una característica de SQL Server. Oracle puede o no puede tener su propia característica similar, no sé.
    • No, pero echa un vistazo Udt y ntypes. Un UDT es similar a una clase, de una ntype a una colección o lista. He pasado de objetos muy complejos entre .net y la base de datos utilizando este mecanismo. Necesitas usar ODP.net y usted necesita estar consciente de que la versión también como soporte para tipos definidos por el usuario fue añadido relativamente recientemente.
    • thx por la info, voy a echarle un vistazo

  2. 49

    El siguiente ejemplo ilustra el uso de un DataTable o un IEnumerable<SqlDataRecord>:

    Código SQL

    CREATE TABLE dbo.PageView
    (
        PageViewID BIGINT NOT NULL CONSTRAINT pkPageView PRIMARY KEY CLUSTERED,
        PageViewCount BIGINT NOT NULL
    );
    CREATE TYPE dbo.PageViewTableType AS TABLE
    (
        PageViewID BIGINT NOT NULL
    );
    CREATE PROCEDURE dbo.procMergePageView
        @Display dbo.PageViewTableType READONLY
    AS
    BEGIN
        MERGE INTO dbo.PageView AS T
        USING @Display AS S
        ON T.PageViewID = S.PageViewID
        WHEN MATCHED THEN UPDATE SET T.PageViewCount = T.PageViewCount + 1
        WHEN NOT MATCHED THEN INSERT VALUES(S.PageViewID, 1);
    END

    De Código De C#

    private static void ExecuteProcedure(bool useDataTable, string connectionString, IEnumerable<long> ids) {
    using (SqlConnection connection = new SqlConnection(connectionString)) {
    connection.Open();
    using (SqlCommand command = connection.CreateCommand()) {
    command.CommandText = "dbo.procMergePageView";
    command.CommandType = CommandType.StoredProcedure;
    SqlParameter parameter;
    if (useDataTable) {
    parameter = command.Parameters.AddWithValue("@Display", CreateDataTable(ids));
    }
    else {
    parameter = command.Parameters.AddWithValue("@Display", CreateSqlDataRecords(ids));
    }
    parameter.SqlDbType = SqlDbType.Structured;
    parameter.TypeName = "dbo.PageViewTableType";
    command.ExecuteNonQuery();
    }
    }
    }
    private static DataTable CreateDataTable(IEnumerable<long> ids) {
    DataTable table = new DataTable();
    table.Columns.Add("ID", typeof(long));
    foreach (long id in ids) {
    table.Rows.Add(id);
    }
    return table;
    }
    private static IEnumerable<SqlDataRecord> CreateSqlDataRecords(IEnumerable<long> ids) {
    SqlMetaData[] metaData = new SqlMetaData[1];
    metaData[0] = new SqlMetaData("ID", SqlDbType.BigInt);
    SqlDataRecord record = new SqlDataRecord(metaData);
    foreach (long id in ids) {
    record.SetInt64(0, id);
    yield return record;
    }
    }
    • Esto me ayudó, gracias!
    • estaba tratando de obtener tvp de trabajo de lo que he encontrado en sqlperformance.com/2012/08/t-sql-queries/… , pero seguía recibiendo dbnull valores. Su ejemplo acabó trabajando para mí, podría ser el parámetro.typename. Gracias!
    • PD: Para aquellos que no deseen crear un tipo personalizado para ello, una solución es pasar los datos de tipo xml, luego de la consulta en contra de eso.

Dejar respuesta

Please enter your comment!
Please enter your name here