Pregunta

¿Cuál es la mejor manera de escribir una consulta con la cláusula en Dapper Orm cuando la lista de valores para la cláusula in proviene de la lógica de negocios? Por ejemplo, digamos que tengo una consulta:

SELECT * 
  FROM SomeTable 
 WHERE id IN (commaSeparatedListOfIDs)

los commaSeparatedListOfIDs se está pasando de la lógica de negocios y puede ser cualquier tipo de IEnumerable(of Integer). ¿Cómo construiría una consulta en este caso? ¿Tengo que hacer lo que he estado haciendo hasta ahora, que es básicamente la concatenación de cadenas o hay algún tipo de técnica de mapeo de parámetros avanzados que no conozca?

¿Fue útil?

Solución

Dapper admite esto directamente. Por ejemplo...

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

Otros consejos

Directamente del Página de inicio del proyecto Github:

Dapper le permite pasar en IEnumerable y parametrizará automáticamente su consulta.

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 });

Será traducido a:

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

Si tu IN La cláusula es demasiado grande para manejar MSSQL, puede usar un TableValueParameter con elegante con bastante facilidad.

  1. Cree su tipo TVP en MSSQL:

    CREATE TYPE [dbo].[MyTVP] AS TABLE([ProviderId] [int] NOT NULL)
    
  2. Crear un DataTable con las mismas columnas que el TVP y llévalo con valores

    var tvpTable = new DataTable();
    tvpTable.Columns.Add(new DataColumn("ProviderId", typeof(int)));
    // fill the data table however you wish
    
  3. Modifique su consulta elegante para hacer un INNER JOIN En la mesa de TVP:

    var query = @"SELECT * FROM Providers P
        INNER JOIN @tvp t ON p.ProviderId = t.ProviderId";
    
  4. Pase el DataTable en su llamada de consulta Dapper

    sqlConn.Query(query, new {tvp = tvpTable.AsTableValuedParameter("dbo.MyTVP")});
    

Esto también funciona fantásticamente cuando desea realizar una actualización masiva de varias columnas: simplemente cree un TVP y haga un UPDATE con una unión interna al TVP.

Esta es posiblemente la forma más rápida de consultar una gran cantidad de filas con elegante usando una lista de ID. Te prometo que esto es más rápido que casi cualquier otra forma en que se te ocurra (con la posible excepción de usar un TVP como se da en otra respuesta, y que no he probado, pero sospecho que puede ser más lento porque tú todavía tengo que llenar el TVP). Está planetas más rápido que el dapper usando IN sintaxis y universos Más rápido que el marco de la entidad fila por fila. E incluso es continentes más rápido que pasar en una lista de VALUES o UNION ALL SELECT elementos. Se puede extender fácilmente para usar una tecla de múltiples columnas, solo agregue las columnas adicionales al DataTable, la tabla temperada y las condiciones de unión.

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;
   }
}

Tenga en cuenta que necesita aprender un poco sobre insertos a granel. Hay opciones sobre los desencadenantes de disparo (el valor predeterminado es no), respetando restricciones, bloqueando la tabla, permitiendo inserciones concurrentes, etc.

También asegúrese de no envolver a los paréntesis alrededor de su cadena de consulta así:

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

Tuve esta causa un error de sintaxis SQL usando Dapper 1.50.2, fijado al eliminar los paréntesis

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

Está no es necesario Para agregar () En la cláusula Where como lo hacemos en un SQL regular. Porque Dapper hace eso automáticamente para nosotros. Aquí está el syntax:-

const string SQL = "SELECT IntegerColumn, StringColumn FROM SomeTable WHERE IntegerColumn IN @listOfIntegers";

var conditions = new { listOfIntegers };

var results = connection.Query(SQL, conditions);

En mi caso he usado esto:

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

Mi variable "IDS" en la segunda línea es un Ienumerable de cuerdas, también pueden ser enteros.

En mi experiencia, la forma más amigable de lidiar con esto es tener una función que convierta una cadena en una tabla de valores.

Hay muchas funciones de divisor disponibles en la web, encontrará una fácilmente una para cualquiera si su sabor de SQL.

Entonces puedes hacer ...

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

O

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

(O similar)

Ejemplo para Postgres:

string sql = "SELECT * FROM SomeTable WHERE id = ANY(@ids)"
var results = conn.Query(sql, new { ids = new[] { 1, 2, 3, 4, 5 }});
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top