Pergunta

Ao usar métodos SetFirstResult(start) e SetMaxResults(count) implementar a paginação tenho notado que a consulta gerada apenas faz um select top count * from some_table e ele não leva o parâmetro start em conta ou, pelo menos não no nível de banco de dados. Parece que se eu instruir NHibernate para executar a consulta a seguir:

var users = session.CreateCriteria<User>()
                   .SetFirstResult(100)
                   .SetMaxResults(5)
                   .List<User>();

105 registros irão transitar entre o servidor de banco de dados ea aplicação que terá o cuidado de retirar os primeiros 100 registros. Com tabelas contendo várias linhas isso poderia ser um problema.

eu tenho verificado que, com uma SQLite banco de dados NHibernate aproveita as palavras-chave OFFSET e LIMIT para filtrar os resultados no nível do banco de dados. Estou ciente de que não há nenhum equivalente da palavra-chave OFFSET e ROWNUM da Oracle no SQL Server 2000 mas existe alguma solução? Como sobre o SQL Server 2005/2008?

Foi útil?

Solução

T-SQL, a variante da linguagem SQL que usa o Microsoft SQL Server, não tem uma cláusula limit. Ele tem um modificador select top {...} que você vê NHibernate aproveitando com o SQL Server 2000.

Com o SQL Server 2005, a Microsoft introduziu a função Row_Number() over (order by {...}) que pode ser usado como um substituto para a cláusula limit, e você pode ver NHibernate aproveitando que com o SQL Server 2005/2008.

A consulta para SQLite pode parecer

select c.[ID], c.[Name]
from [Codes] c
where c.[Key] = 'abcdef'
order by c.[Order]
limit 20 offset 40

enquanto uma consulta semelhante para o SQL Server 2005 pode parecer

select c.[ID], c.[Name]
from (
    select c.[ID], c.[Name], c.[Order]
        , [!RowNum] = Row_Number() over (order by c.[Order])
    from [Codes] c
    where c.[Key] = 'abcdef'
) c
where c.[!RowNum] > 40 and c.[!RowNum] <= 60
order by c.[Order]

ou, usando expressões de tabela comum, que pode parecer

with
    [Source] as (
        select c.[ID], c.[Name], c.[Order]
            , [!RowNum] = Row_Number() over (order by c.[Order])
        from [Codes] c
        where c.[Key] = 'abcdef'
    )
select c.[ID], c.[Name]
from [Source] c
where c.[!RowNum] > 40 and c.[!RowNum] <= 60
order by c.[Order]

Há uma maneira de fazê-lo em SQL Server 2000, bem

select c.[ID], c.[Name]
from (
    select top 20 c.[ID], c.[Name], c.[Order]
    from (
        select top 60 c.[ID], c.[Name], c.[Order]
        from [Codes] c
        where c.[Key] = 'abcdef'
        order by c.[Order]
    ) c
    order by c.[Order] desc
) c
order by c.[Order]

Outras dicas

Nhibernate é suficiente inteligente para consulta otimizar. Se seleccionar primeiro 10 linhas que vai usar declaração TOP. Se você selecionar Não primeiras filas, então ele irá usar RowNum.

No SQL 2000 não há nenhuma função RowNum, é por isso que é impossível com consulta habitual para selecionar o número necessário de linhas. Para o SQL 2000 como eu sei que para tal vista de otimização foram utilizados.

Em sql 2005/2008 consulta irá selecionar apenas linhas necessárias.


Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top