2011-06-02 15 views
7

A continuación se muestra el código que estoy usando para devolver una lista paginada de objetos:Dapper - Mapeo de múltiples con un único valor de retorno

string query2 = @" 
     select count(*) as TotalCount from blogposts p where p.Deleted = 0 and p.PublishDate <= @date 
     select * from (
      select p.*, 
      row_number() over(order by publishdate desc) as rownum 
      from blogposts as p 
      where p.Deleted = 0 and p.PublishDate <= @date 
     ) seq 
     where seq.rownum between @x and @y"; 

using (var cn = new SqlConnection(connectionString)) 
{ 
    cn.Open(); 
    using (var multi = cn.QueryMultiple(query2, new { x= lower, y = upper, date = DateTime.UtcNow })) 
    { 
     var totalCount = multi.Read<int>().Single(); 
     var posts = multi.Read<PostModel>().ToList(); 
     return new PagedList<PostModel>(posts, page, pageSize, x => totalCount); 
    } 
} 

Aunque esto funciona, significa que tengo que definir mi criterio dos veces, una vez para la consulta de conteo y una para la consulta de conjunto de resultados. En lugar de recurrir a la concatenación de cadenas, puedo ejecutar una sola consulta:

 string query = @" 
       select * from (select p.*, 
       row_number() over(order by publishdate desc) as rownum, 
       count(*) over() as TotalCount 
       from blogposts as p) seq 
       where seq.rownum between @x and @y"; 

Sin embargo, no parecen capaces de trazar esta usando Dapper. No puedo usar el mismo método que el anterior porque no hay resultados múltiples. Intenté usar el mapeo múltiple, pero esto espera devolver un IEnumerable.

¿Cómo me asignaría a lo siguiente?

public class PostList 
    { 
     public IEnumerable<PostModel> Posts; 
     public int TotalCount { get; set; } 
    } 

Gracias

Ben

Respuesta

6

Bueno ... no ...

Usted tendría que modificar su PostModel para incluir un TotalCount propiedad ... que es realmente feo. O ejecute una dinámica y vuelva a asignarla en un Select que también es feo.

Usted ve, usted está devolviendo la cuenta (*) N veces con count(*) over() ... es un truco, el uso de este truco no es necesariamente más rápido. He medido que es más lento que ejecutar una consulta doble en algunos de mis escenarios, en particular, puede atajar algunos índices en el select count(*) ya que no está seleccionando todas las columnas. Además, el truco desactiva ciertas optimizaciones de paginación, por ejemplo, no puede agregar select top N a la consulta.

Mi recomendación acerca de las consultas de paginación sería obtener la indexación correcta, es la clave. Mida el rendimiento y vea si este truco realmente ayuda (cuando la indexación correcta está en su lugar).

Sigo las preocupaciones sobre la concatenación de cadenas, pero siempre puedes definir métodos generales de ayuda para eso.

+0

Gracias por los comentarios. Creo que me quedaré con la doble consulta y construiré algunos ayudantes para mantener las cosas secas. –