当IN子句的值列表来自业务逻辑时,使用Dapper ORM编写带有IN子句的查询的最佳方法是什么?例如,假设我有一个查询:

SELECT * 
  FROM SomeTable 
 WHERE id IN (commaSeparatedListOfIDs)

commaSeparatedListOfIDs是从业务逻辑传入的,它可以是任何类型的IEnumerable(Integer)。在这种情况下如何构造查询?我是否需要做我目前所做的基本上是字符串连接还是有一些我不知道的高级参数映射技术?


当前回答

还要确保你没有像这样用圆括号括起你的查询字符串:

SELECT Name from [USER] WHERE [UserId] in (@ids)

我使用Dapper 1.50.2导致SQL语法错误,通过删除括号来修复

SELECT Name from [USER] WHERE [UserId] in @ids

其他回答

Dapper直接支持这一点。例如……

string sql = "SELECT * FROM SomeTable WHERE id IN @ids"
var results = conn.Query(sql, new { ids = new[] { 1, 2, 3, 4, 5 }});

除非你正在使用Postgres,在这种情况下,请参阅这个答案

如果你的IN子句太大,MSSQL无法处理,你可以很容易地使用一个TableValueParameter与Dapper。

Create your TVP type in MSSQL: CREATE TYPE [dbo].[MyTVP] AS TABLE([ProviderId] [int] NOT NULL) Create a DataTable with the same column(s) as the TVP and populate it with values var tvpTable = new DataTable(); tvpTable.Columns.Add(new DataColumn("ProviderId", typeof(int))); // fill the data table however you wish Modify your Dapper query to do an INNER JOIN on the TVP table: var query = @"SELECT * FROM Providers P INNER JOIN @tvp t ON p.ProviderId = t.ProviderId"; Pass the DataTable in your Dapper query call sqlConn.Query(query, new {tvp = tvpTable.AsTableValuedParameter("dbo.MyTVP")});

当您想要对多个列进行大规模更新时,这也非常有效——只需构建一个TVP,并使用到TVP的内部连接执行update。

在我的例子中,我使用了这个:

var query = "select * from table where Id IN @Ids";
var result = conn.Query<MyEntity>(query, new { Ids = ids });

我的变量“ids”在第二行是一个字符串的IEnumerable,我猜他们也可以是整数。

根据我的经验,处理这个问题最友好的方法是使用一个函数将字符串转换为值表。

在网络上有很多可用的分配器函数,如果你喜欢SQL,你很容易就能找到一个。

然后你可以做…

SELECT * FROM table WHERE id IN (SELECT id FROM split(@list_of_ids))

Or

SELECT * FROM table INNER JOIN (SELECT id FROM split(@list_of_ids)) AS list ON list.id = table.id

(或相似的)

还要确保你没有像这样用圆括号括起你的查询字符串:

SELECT Name from [USER] WHERE [UserId] in (@ids)

我使用Dapper 1.50.2导致SQL语法错误,通过删除括号来修复

SELECT Name from [USER] WHERE [UserId] in @ids