SELECT * FROM X WHERE使用Dapper ORM标识IN(...)

时间:2011-12-05 15:59:31

标签: .net sql dapper

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

SELECT * 
  FROM SomeTable 
 WHERE id IN (commaSeparatedListOfIDs)

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

9 个答案:

答案 0 :(得分:292)

Dapper直接支持此功能。例如......

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

答案 1 :(得分:53)

直接来自GitHub project homepage

  

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

答案 2 :(得分:32)

如果你的IN子句对于MSSQL来说太大而无法处理,你可以很容易地将TableValueParameter与Dapper一起使用。

  1. 在MSSQL中创建您的TVP类型:

    CREATE TYPE [dbo].[MyTVP] AS TABLE([ProviderId] [int] NOT NULL)
    
  2. 使用与TVP相同的列创建DataTable,并使用值填充

    var tvpTable = new DataTable();
    tvpTable.Columns.Add(new DataColumn("ProviderId", typeof(int)));
    // fill the data table however you wish
    
  3. 修改您的Dapper查询以在TVP表格上执行INNER JOIN

    var query = @"SELECT * FROM Providers P
        INNER JOIN @tvp t ON p.ProviderId = t.ProviderId";
    
  4. 在Dapper查询调用中传递DataTable

    sqlConn.Query(query, new {tvp = tvpTable.AsTableValuedParameter("dbo.MyTVP")});
    
  5. 当您想要对多个列进行大规模更新时,这也非常有用 - 只需构建一个TVP,然后通过内部联接为TVP执行UPDATE

答案 3 :(得分:10)

这可能是使用ID列表使用Dapper查询大量行的最快方法。我向你保证这比你能想到的几乎任何其他方式都要快(除了在另一个答案中使用TVP可能的例外情况,我没有测试过,但我怀疑可能会慢一点,因为你仍然必须填充TVP)。 planets 比使用IN语法的Dapper和比实体框架逐行更快的 Universe 更快。它甚至比传递VALUESUNION 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;
   }
}

请注意,您需要了解一下批量插入内容。有关触发触发器的选项(默认为no),尊重约束,锁定表,允许并发插入等等。

答案 4 :(得分:6)

在WHERE子句中添加angular.element(document.querySelector('#table')).append($compile(tableHTML)$scope)); 与在常规SQL中一样,没有必要。因为Dapper会自动为我们做这件事。这是(): -

syntax

答案 5 :(得分:5)

另外,请确保不要在查询字符串周围包括括号,如下所示:

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

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

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

答案 6 :(得分:3)

就我而言,我已经使用了这个:

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

我的变量&#34; ids&#34;在第二行是一个IEnumerable字符串,我猜它们也可以是整数。

答案 7 :(得分:2)

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

网上有很多可用的分割器功能,如果你喜欢SQL的话,你可以轻松找到一个。

然后你可以......

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

或者

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

(或类似)

答案 8 :(得分:2)

postgres示例:

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