2011-08-08 2 views
29

Próbuję przekazać parametr wartości tabeli do procedury składowanej, ale nadal otrzymuję wyjątek (patrz poniżej).Jak przekazać parametr wartości tabeli

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();

Typ jest zdefiniowany na serwerze tak:

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

Próbowałem przechodzącą sharedPdfs jako List<int> i IQueryable<int>, ale wciąż otrzymuję następujący wyjątek:

Object must implement IConvertible.

Ktoś wie, co robię źle? Dokumentacja sugeruje, że powinienem być w stanie przekazać listę jako TVP, ale nie podam żadnych przykładów.

Dziękuję.

+0

Jak to 'getPermittedUsers' oświadczył? –

+0

To jest daleki strzał, ale czy próbowałeś przekazać 'int []'? –

+4

Musisz użyć 'DataTable'. – ChaosPandion

Odpowiedz

12

Parametr można przekazać jako DataTable, IEnumerable<SqlDataRecord> lub DbDataReader.

+0

? do SQLCommand Jesteś pewien? –

+1

Tak, są to obsługiwane typy dla parametru wartości tabeli w SqlCommand. Pełna dokumentacja znajduje się tutaj: http://msdn.microsoft.com/en-us/library/bb675163.aspx. Zobacz 1/3 drogi w dół: "System.Data.SqlClient obsługuje zapełnianie wartościami tabelarycznymi z DataTable, DbDataReader lub System.Collections.Generic.IEnumerable ([T: System.Collections.Generic.IEnumerable' 1)] obiektów. " –

+1

jest to również możliwe w Oracle? –

42

Poniższy przykład ilustruje użyciem albo DataTable lub IEnumerable<SqlDataRecord>:

kod 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 

C# Code

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

Pomogło mi to, dzięki! – s0nica

+0

próbowałem uzyskać działanie tvp z tego, co znalazłem na http://sqlperformance.com/2012/08/t-sql-queries/splitting-strings-now-with-less-t-sql, ale ciągle uzyskiwałem wartości dbnull. Twój przykład zakończył się dla mnie, może być parametrem.typename. Dzięki! – Phil

+0

NB: Dla tych, którzy nie chcą tworzyć niestandardowego typu, rozwiązaniem jest przekazanie danych jako typu xml, a następnie zapytanie o nie. – JohnLBevan