当IN子句的值列表来自业务逻辑时,使用Dapper ORM使用IN子句编写查询的最佳方法是什么?例如,假设我有一个查询:
SELECT *
FROM SomeTable
WHERE id IN (commaSeparatedListOfIDs)
Run Code Online (Sandbox Code Playgroud)
它commaSeparatedListOfIDs是从业务逻辑传入的,它可以是任何类型的IEnumerable(of Integer).在这种情况下,我将如何构造查询?我是否必须做到目前为止我一直在做的事情,这基本上是字符串连接,还是有一些我不知道的高级参数映射技术?
Luk*_*keH 333
Dapper直接支持这一点.例如...
string sql = "SELECT * FROM SomeTable WHERE id IN @ids"
var results = conn.Query(sql, new { ids = new[] { 1, 2, 3, 4, 5 }});
Run Code Online (Sandbox Code Playgroud)
Fac*_*tic 60
直接来自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 });
Run Code Online (Sandbox Code Playgroud)
将被翻译为:
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
Run Code Online (Sandbox Code Playgroud)
Mr.*_*. T 37
如果你的IN子句对于MSSQL来说太大了,你可以很容易地将TableValueParameter与Dapper一起使用.
在MSSQL中创建您的TVP类型:
CREATE TYPE [dbo].[MyTVP] AS TABLE([ProviderId] [int] NOT NULL)
Run Code Online (Sandbox Code Playgroud)创建一个DataTable与TVP相同的列,并用值填充它
var tvpTable = new DataTable();
tvpTable.Columns.Add(new DataColumn("ProviderId", typeof(int)));
// fill the data table however you wish
Run Code Online (Sandbox Code Playgroud)修改您的Dapper查询以INNER JOIN在TVP表上执行:
var query = @"SELECT * FROM Providers P
INNER JOIN @tvp t ON p.ProviderId = t.ProviderId";
Run Code Online (Sandbox Code Playgroud)在Dapper查询调用中传递DataTable
sqlConn.Query(query, new {tvp = tvpTable.AsTableValuedParameter("dbo.MyTVP")});
Run Code Online (Sandbox Code Playgroud)当您想要对多列进行大规模更新时,这也非常有用 - 只需构建一个TVP并UPDATE使用内部联接进行TVP.
San*_*́́́ 19
postgres 示例:
string sql = "SELECT * FROM SomeTable WHERE id = ANY(@ids)"
var results = conn.Query(sql, new { ids = new[] { 1, 2, 3, 4, 5 }});
Run Code Online (Sandbox Code Playgroud)
Eri*_*ikE 12
这可能是使用ID列表使用Dapper查询大量行的最快方法.我向你保证,这比你能想到的几乎任何其他方式都要快(除了在另一个答案中使用TVP的可能例外,我没有测试过,但我怀疑可能会因为你仍然需要填充而变慢TVP).它是 行星比小巧玲珑的使用速度更快IN的语法和语义层比排实体框架排得更快.它甚至比传递列表VALUES或UNION ALL SELECT项目更快.它可以很容易地扩展为使用多列键,只需将额外的列添加到DataTable临时表和连接条件.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,您需要了解有关批量插入的一些信息.有关触发触发器的选项(默认为no),尊重约束,锁定表,允许并发插入等等.
还要确保不要像这样在查询字符串周围加上括号:
SELECT Name from [USER] WHERE [UserId] in (@ids)
Run Code Online (Sandbox Code Playgroud)
我使用Dapper 1.50.2导致了SQL语法错误,已通过删除括号进行了修复
SELECT Name from [USER] WHERE [UserId] in @ids
Run Code Online (Sandbox Code Playgroud)
这是没有必要添加()在WHERE子句中,我们在一个普通的SQL做.因为Dapper会自动为我们做这件事.这是syntax: -
const string SQL = "SELECT IntegerColumn, StringColumn FROM SomeTable WHERE IntegerColumn IN @listOfIntegers";
var conditions = new { listOfIntegers };
var results = connection.Query(SQL, conditions);
Run Code Online (Sandbox Code Playgroud)