SQL Server 2008 (eller nyere)
Først skal du oprette følgende to objekter i din database:
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 i din C#-kode:
// 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
Hvis du bruger SQL Server 2005, vil jeg stadig anbefale en split-funktion frem for XML. Først skal du oprette en funktion:
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 din lagrede procedure bare være:
CREATE PROCEDURE dbo.DoSomethingWithEmployees
@List VARCHAR(MAX)
AS
BEGIN
SET NOCOUNT ON;
SELECT EmployeeID = Item FROM dbo.SplitInts(@List, ',');
END
GO
Og i din C#-kode skal du blot sende listen som '1,2,3,12'
...
Jeg synes, at metoden til at passere tabelværdierede parametre forenkler vedligeholdelsen af en løsning, der bruger den og ofte har øget ydeevne sammenlignet med andre implementeringer, herunder XML og strengopdeling.
Indgangene er klart definerede (ingen skal gætte, om afgrænsningstegnet er et komma eller semikolon), og vi har ikke afhængigheder af andre behandlingsfunktioner, der ikke er indlysende uden at inspicere koden for den lagrede procedure.
Sammenlignet med løsninger, der involverer brugerdefineret XML-skema i stedet for UDT'er, involverer dette et tilsvarende antal trin, men efter min erfaring er det langt enklere kode at administrere, vedligeholde og læse.
I mange løsninger har du måske kun brug for en eller nogle få af disse UDT'er (Brugerdefinerede typer), som du genbruger til mange lagrede procedurer. Som med dette eksempel er det almindelige krav at passere en liste over ID-pegere, funktionsnavnet beskriver hvilken kontekst disse Id'er skal repræsentere, typenavnet skal være generisk.