A paginação e o Entity Framework

0

Pergunta

No meu aplicativo móvel, tento recuperar dados de uma tabela do meu banco de dados SQL Server. Eu estou usando o EF e eu tento usar a paginação para um melhor desempenho. Eu precisa para obter dados a partir do último elemento da tabela. portanto, se a tabela tem 20 linhas, o que eu preciso, para a página 0, IDs de 20, 19, 18, 17, 16, em seguida, para a página 1 IDs de 15, 14, 13, 12, 11, e assim por diante...

O problema é: e se, enquanto o usuário "A" é a transferência de dados de tabela, o usuário "B" adicionar linha? Se o usuário "A" obter Página 0 (para IDs 20, 19, 18, 17, 16), e o usuário "B" no mesmo momento em adicionar linha (modo de IDENTIFICAÇÃO 21), com o clássico de consulta, o usuário "A" para a página 1 terá IDs 16, 15, 14, 13, 12... portanto, outra vez 16 de IDENTIFICAÇÃO

Meu código é muito simples:

int RecordsForPagination = 5; 
var list = _context.NameTable
                   .Where(my_condition)
                   .OrderByDescending(my_condition_for ordering)
                   .Skip (RecordsForPagination * Page)
                   .Take (RecordsForPagination)
                   .ToList();

Claro Page é int, que vêm de frontend.

Como posso resolver o problema?

Eu achei uma solução, mas eu não sei se é o ideal. Eu poderia usar

.SkipWhile(x => x.ID >= LastID) 

em vez disso

.Skip (RecordsForPagination * Page)

e, claro, LastID sempre é enviado a partir do frontend.

Você acha que o desempenho é sempre bom com esse código? Existe uma solução melhor?

entity-framework linq sql-server
2021-11-22 23:06:34
1

Melhor resposta

1

Os impactos no desempenho vai depender muito de seu Índice do SQL implementação e a cláusula order by. Mas não é bem uma pergunta, sobre o desempenho, como é sobre obter os resultados esperados.

Estouro de pilha é um grande exemplo, onde há um volume de actividade, de tal forma que quando você chegar ao final de qualquer página, próxima página poderá conter registros da página que você acabou de ver, porque o conjunto de registros subjacente mudou (mais postos de ter sido adicionadas)

Eu trago isso porque em um sistema live é geralmente aceitos e, em alguns casos, uma esperado de comportamento. Como os desenvolvedores agradecemos adicionado despesas gerais de tentar manter um único conjunto de resultados e reconhecer que não é geralmente muito menor valor na tentativa de evitar o que parece duplicações como você iterar as páginas.

Muitas vezes é suficiente para explicar aos usuários por que isso ocorre, em muitos casos, eles irão aceitá-lo

Se ele foi importante para manter o lugar no original, o resultado definido, você deve restringir a consulta com um Where cláusula, mas você vai precisar para recuperar o Id ou o carimbo de data / hora da consulta original. No seu caso, você está tentando usar LastIDmas , para obter o último ID exigiria uma consulta separada por si próprio, porque a cláusula orderby irá afetá-lo.

Você não pode realmente usar .SkipWhile(x => x.ID >= LastID) para isso, porque ignorar é um processo sequencial que é afetado pela ordem e é dis-envolvimento de primeira instância, que a expressão avalia para false, então, se o seu fim não é baseado em Id, seu ignorar enquanto pode resultar está ignorando registros não em todos.

int RecordsForPagination = 5; 
int? MaxId = null;
...
var query = _context.NameTable.Where(my_condition);
// We need the Id to constraint the original search
if (!MaxId.HasValue)
    MaxId = query.Max(x => x.ID);

var list = query.Where(x => x.ID <= MaxId)
                .OrderByDescending(my_condition_for ordering)
                .Skip(RecordsForPagination * Page)
                .Take(RecordsForPagination);
                .ToList();

É, geralmente, mais simples para filtrar por um momento como este é conhecido a partir do cliente sem um round trip para o DB, mas dependendo da aplicação da filtragem em datas pode ser menos eficiente.

2021-11-22 23:55:04

A minha intenção era a de não obter LastID de DB (porque, como você disse, isso seria afetado por Db em si). a minha intenção era esta: - Frontend obter Página 0 e o resultado são os IDs de 20, 19, 18, 17, 16 - Frontend obter Página 1 e passa para o backend dois param: Página 1 e LastID da Página anterior (neste caso LastID = 16) -> então o resultado será IDs 15, 14, 13, 12, 11... e assim por diante. meu inglês não é perfeito... estamos dizendo a mesma coisa?
user1106897

@user1106897 A técnica Chris se refere é chamado de conjunto de chaves de Paginação, e, geralmente, é muito melhor do que a paginação por linhas, o que é que você está falando
Charlieface

Muito é também uma questão de desempenho: paginação por linhas é altamente ineficiente como todas as linhas anteriores têm que ser lidos a cada vez. Considerando que a paginação por chave (ou hora, nesse caso) é muito eficiente se houver um índice de suporte
Charlieface

Charlie cara muito obrigado pelo link, realmente apreciado. Vou tentar usar conselhos
user1106897

Obrigado @Charlieface o desempenho de observação foi mais deveria ser "esqueça o desempenho, SkipWhile(por identificação) não vai resolver o problema se você alterar a ordem de" Grande ligação muito!
Chris Schaller

Em outros idiomas

Esta página está em outros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................