Esta é possivelmente a maneira mais rápida de consultar um grande número de linhas com o Dapper usando uma lista de IDs. Eu prometo a você que isso é mais rápido do que quase qualquer outra maneira em que você possa pensar (com a possível exceção de usar um TVP como dado em outra resposta, e que eu não testei, mas suspeito que possa ser mais lento porque você ainda precisa preencher TVP). É planetas mais rápido que o Dapper usando IN
sintaxe e universos mais rápido que o Entity Framework linha por linha. E é até continentes mais rápido do que passar em uma lista de VALUES
ou UNION ALL SELECT
itens. Ele pode ser facilmente estendido para usar uma chave de várias colunas, basta adicionar as colunas extras às DataTable
, tabela temporária e condições de junção.
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;
}
}
Esteja ciente de que você precisa aprender um pouco sobre as inserções em massa. Existem opções sobre acionar acionadores (o padrão é não), respeitar restrições, bloquear a tabela, permitir inserções simultâneas e assim por diante.