SQL Server 2008 (ou plus récent)
Tout d'abord, dans votre base de données, créez les deux objets suivants:
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
Maintenant dans votre code 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
Si vous utilisez SQL Server 2005, je recommanderais toujours une fonction partagée sur XML. Créez d'abord une fonction:
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
Maintenant, votre procédure stockée peut simplement être:
CREATE PROCEDURE dbo.DoSomethingWithEmployees
@List VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
SELECT EmployeeID = Item FROM dbo.SplitInts(@List, ',');
END
GO
Et dans votre code C #, il vous suffit de passer la liste en tant que '1,2,3,12'
...
Je trouve que la méthode de passage à travers les paramètres de valeur de table simplifie la maintenabilité d'une solution qui l'utilise et a souvent des performances accrues par rapport à d'autres implémentations, y compris XML et le fractionnement de chaînes.
Les entrées sont clairement définies (personne n'a à deviner si le délimiteur est une virgule ou un point-virgule) et nous n'avons pas de dépendances sur d'autres fonctions de traitement qui ne sont pas évidentes sans inspecter le code de la procédure stockée.
Comparé aux solutions impliquant un schéma XML défini par l'utilisateur au lieu d'UDT, cela implique un nombre similaire d'étapes, mais d'après mon expérience, il est beaucoup plus simple de gérer, de maintenir et de lire du code.
Dans de nombreuses solutions, il se peut que vous n'ayez besoin que d'un ou de quelques-uns de ces UDT (types définis par l'utilisateur) que vous réutilisez pour de nombreuses procédures stockées. Comme pour cet exemple, l'exigence courante est de passer par une liste de pointeurs d'ID, le nom de la fonction décrit le contexte que ces ID doivent représenter, le nom du type doit être générique.