SQL Server 2008 (of nieuwer)
Maak eerst in uw database de volgende twee objecten:
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
Nu in uw C#-code:
// 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
Als u SQL Server 2005 gebruikt, zou ik nog steeds een split-functie over XML aanbevelen. Maak eerst een functie:
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
Nu kan uw opgeslagen procedure gewoon zijn:
CREATE PROCEDURE dbo.DoSomethingWithEmployees
@List VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
SELECT EmployeeID = Item FROM dbo.SplitInts(@List, ',');
END
GO
En in je C#-code hoef je de lijst alleen maar door te geven als '1,2,3,12'
...
Ik vind dat de methode om parameters met tabelwaarde door te geven de onderhoudbaarheid vereenvoudigt van een oplossing die deze gebruikt en vaak betere prestaties heeft in vergelijking met andere implementaties, waaronder XML en het splitsen van strings.
De ingangen zijn duidelijk gedefinieerd (niemand hoeft te raden of het scheidingsteken een komma of een puntkomma is) en we hebben geen afhankelijkheden van andere verwerkingsfuncties die niet duidelijk zijn zonder de code voor de opgeslagen procedure te inspecteren.
Vergeleken met oplossingen met door de gebruiker gedefinieerd XML-schema in plaats van UDT's, omvat dit een vergelijkbaar aantal stappen, maar in mijn ervaring is het veel eenvoudiger code te beheren, onderhouden en lezen.
In veel oplossingen hebt u mogelijk slechts een of enkele van deze UDT's (door de gebruiker gedefinieerde typen) nodig die u voor veel opgeslagen procedures opnieuw gebruikt. Net als bij dit voorbeeld is de algemene vereiste dat u een lijst met ID-pointers doorloopt, de functienaam beschrijft welke context die ID's moeten vertegenwoordigen, en de typenaam moet generiek zijn.