SQL Server 2008 (o successivo)
Innanzitutto, nel tuo database, crea i seguenti due oggetti:
CREATE TYPE dbo.IDList
AS TABLE
(
ID INT
);
GO
CREATE PROCEDURE dbo.DoSomethingWithEmployees
@List AS dbo.IDList READONLY
AS
BEGIN
SET NOCOUNT ON;
SELECT ID FROM @List;
END
GO
Ora nel tuo codice C#:
// Obtain your list of ids to send, this is just an example call to a helper utility function
int[] employeeIds = GetEmployeeIds();
DataTable tvp = new DataTable();
tvp.Columns.Add(new DataColumn("ID", typeof(int)));
// populate DataTable from your List here
foreach(var id in employeeIds)
tvp.Rows.Add(id);
using (conn)
{
SqlCommand cmd = new SqlCommand("dbo.DoSomethingWithEmployees", conn);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter tvparam = cmd.Parameters.AddWithValue("@List", tvp);
// these next lines are important to map the C# DataTable object to the correct SQL User Defined Type
tvparam.SqlDbType = SqlDbType.Structured;
tvparam.TypeName = "dbo.IDList";
// execute query, consume results, etc. here
}
SQL Server 2005
Se stai usando SQL Server 2005, consiglierei comunque una funzione divisa su XML. Innanzitutto, crea una funzione:
CREATE FUNCTION dbo.SplitInts
(
@List VARCHAR(MAX),
@Delimiter VARCHAR(255)
)
RETURNS TABLE
AS
RETURN ( SELECT Item = CONVERT(INT, Item) FROM
( SELECT Item = x.i.value('(./text())[1]', 'varchar(max)')
FROM ( SELECT [XML] = CONVERT(XML, '<i>'
+ REPLACE(@List, @Delimiter, '</i><i>') + '</i>').query('.')
) AS a CROSS APPLY [XML].nodes('i') AS x(i) ) AS y
WHERE Item IS NOT NULL
);
GO
Ora la tua procedura memorizzata può essere solo:
CREATE PROCEDURE dbo.DoSomethingWithEmployees
@List VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
SELECT EmployeeID = Item FROM dbo.SplitInts(@List, ',');
END
GO
E nel tuo codice C# devi solo passare l'elenco come '1,2,3,12'
...
Trovo che il metodo per passare attraverso i parametri con valori di tabella semplifichi la manutenibilità di una soluzione che lo utilizza e spesso ha prestazioni migliorate rispetto ad altre implementazioni, inclusi XML e suddivisione delle stringhe.
Gli input sono chiaramente definiti (nessuno deve indovinare se il delimitatore è una virgola o un punto e virgola) e non abbiamo dipendenze da altre funzioni di elaborazione che non sono ovvie senza ispezionare il codice per la procedura memorizzata.
Rispetto alle soluzioni che coinvolgono lo schema XML definito dall'utente anziché gli UDT, ciò comporta un numero simile di passaggi ma nella mia esperienza è un codice molto più semplice da gestire, mantenere e leggere.
In molte soluzioni potrebbe essere necessario solo uno o alcuni di questi UDT (Tipi definiti dall'utente) che riutilizzi per molte stored procedure. Come in questo esempio, il requisito comune è di passare attraverso un elenco di puntatori ID, il nome della funzione descrive il contesto che devono rappresentare quegli ID, il nome del tipo deve essere generico.