Answers:
Dapper直接支持这一点。例如...
string sql = "SELECT * FROM SomeTable WHERE id IN @ids"
var results = conn.Query(sql, new { ids = new[] { 1, 2, 3, 4, 5 }});
IN
子句中的条目限制为2100 。
直接从GitHub项目主页:
Dapper允许您传递IEnumerable并将自动参数化您的查询。
connection.Query<int>(
@"select *
from (select 1 as Id union all select 2 union all select 3) as X
where Id in @Ids",
new { Ids = new int[] { 1, 2, 3 });
将被翻译为:
select *
from (select 1 as Id union all select 2 union all select 3) as X
where Id in (@Ids1, @Ids2, @Ids3)
// @Ids1 = 1 , @Ids2 = 2 , @Ids2 = 3
如果您的IN
子句太大而无法处理MSSQL,则可以很轻松地在Dapper中使用TableValueParameter。
在MSSQL中创建TVP类型:
CREATE TYPE [dbo].[MyTVP] AS TABLE([ProviderId] [int] NOT NULL)
使用DataTable
与TVP相同的列创建一个,并使用值填充
var tvpTable = new DataTable();
tvpTable.Columns.Add(new DataColumn("ProviderId", typeof(int)));
// fill the data table however you wish
修改您的Dapper查询以INNER JOIN
在TVP表上执行以下操作:
var query = @"SELECT * FROM Providers P
INNER JOIN @tvp t ON p.ProviderId = t.ProviderId";
在Dapper查询调用中传递DataTable
sqlConn.Query(query, new {tvp = tvpTable.AsTableValuedParameter("dbo.MyTVP")});
当您要对多个列进行批量更新时,这也非常有用-只需构建一个TVP并UPDATE
使用内部连接到TVP。
ProviderId
使用MyTVP
be PRIMARY KEY CLUSTERED
,因为这为我们解决了性能问题(我们传递的值不包含重复项)。
这可能是使用Dapper使用ID列表查询大量行的最快方法。我向您保证,这比您能想到的几乎任何其他方式都要快(除了使用另一个答案中给出的TVP的可能例外,而且我尚未测试过,但我怀疑这样做可能会较慢,因为您仍然需要填充TVP)。它是 行星比使用小巧玲珑更快IN
的语法和宇宙不是按照行实体框架排得更快。而且甚至比传递一个VALUES
或多个UNION ALL SELECT
项目列表还要快。可以轻松地扩展它以使用多列键,只需将额外的列添加到DataTable
,temp表和联接条件中即可。
public IReadOnlyCollection<Item> GetItemsByItemIds(IEnumerable<int> items) {
var itemList = new HashSet(items);
if (itemList.Count == 0) { return Enumerable.Empty<Item>().ToList().AsReadOnly(); }
var itemDataTable = new DataTable();
itemDataTable.Columns.Add("ItemId", typeof(int));
itemList.ForEach(itemid => itemDataTable.Rows.Add(itemid));
using (SqlConnection conn = GetConnection()) // however you get a connection
using (var transaction = conn.BeginTransaction()) {
conn.Execute(
"CREATE TABLE #Items (ItemId int NOT NULL PRIMARY KEY CLUSTERED);",
transaction: transaction
);
new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, transaction) {
DestinationTableName = "#Items",
BulkCopyTimeout = 3600 // ridiculously large
}
.WriteToServer(itemDataTable);
var result = conn
.Query<Item>(@"
SELECT i.ItemId, i.ItemName
FROM #Items x INNER JOIN dbo.Items i ON x.ItemId = i.ItemId
DROP TABLE #Items;",
transaction: transaction,
commandTimeout: 3600
)
.ToList()
.AsReadOnly();
transaction.Rollback(); // Or commit if you like
return result;
}
}
请注意,您需要了解一些有关批量插入的知识。有关于触发触发器(默认为no),遵守约束,锁定表,允许并发插入等选项。
DataTable
是所必需的大容量插入。如何你插入到临时表50,000个值?
Postgres示例:
string sql = "SELECT * FROM SomeTable WHERE id = ANY(@ids)"
var results = conn.Query(sql, new { ids = new[] { 1, 2, 3, 4, 5 }});