0

I need to pass a list of thousands of IDs to a query as a parameter to filter on, using Dapper.

Even if there wasn't a limit WRT the amount of parameters you can send to SQL Server, looping through the collection and creating numerous parameters is an inelegant solution.

Luckily I've seen that you can send an XML string which the query than can unpack using XTbl.value and .nodes().

But I cannot figure out how to pass this XML string via Dapper.

BCdotWEB
  • 1,009
  • 1
  • 14
  • 35
  • If you want to pass "thousands of IDs to a query", you should look into using [table-valued parameters](https://medium.com/dapper-net/sql-server-specific-features-2773d894a6ae). – mm8 Sep 10 '19 at 12:33

1 Answers1

0

In the end it wasn't that hard, it just took some effort combining various nuggets of knowledge and a bit of trial and error.

This is a simplified version of the query:

SELECT DISTINCT [regular_Person].[Idf] AS [Idf]
    , [regular_Person].[FirstName]
    , [regular_Person].[LastName]

FROM [regular].[Person] [regular_Person]

WHERE [regular_Person].[Idf] IN (
        SELECT Idf
        FROM (
            SELECT Idf = XTbl.value('.', 'NVARCHAR(10)')
            FROM @Idfs.nodes('/root/Idf') AS XD(XTbl)
        ) AS XmlToData
    )

ORDER BY 
    [regular_Person].[LastName]
    , [regular_Person].[FirstName]

It is embedded as an .sql file in my solution, and I read it using my QueryRetriever class -- check https://codereview.stackexchange.com/q/214250/10582 for its code.

The IDs to pass to the query need to be converted to an XML string:

        var idfsAsXml = new XDocument(
                new XElement("root",
                    excelRecords
                        .Select(x => x.Idf)
                        .Distinct()
                        .Select(x => new XElement("Idf", x))))
            .ToString();

I then use Dapper's DynamicParameters to create a parameter:

        var dynamicParameters = new DynamicParameters();
        dynamicParameters.Add("@Idfs", idfsAsXml, DbType.Xml, ParameterDirection.Input);

And then I pass that parameter as DbType.Xml (with ParameterDirection.Input):

        using (var connection = new SqlConnection(_connectionString))
        {
            regularRecords = connection.Query<RegularRecord>(
                    QueryRetriever.GetQuery("GetRegularRecords.sql"),
                    dynamicParameters
                )
                .ToList();
        }

Perhaps this will be of help to others.

BCdotWEB
  • 1,009
  • 1
  • 14
  • 35