Recursos de implementação de listas dinâmicas em interfaces de usuário

imagem

A interface de cada aplicativo moderno, de uma forma ou de outra, contém listas de objetos. Ao trabalhar com eles, o usuário geralmente precisa do mesmo tipo de ações, como classificação, filtragem, exportação e assim por diante. A implementação dessas operações geralmente é complicada pelo fato de as listas poderem ser "dinâmicas". Nesse caso, os dados serão lidos conforme necessário, não apenas do servidor para o cliente, mas também do servidor de banco de dados para o servidor de aplicativos.

Na plataforma aberta e gratuita do lsFusion, todas as listas são dinâmicas por padrão e são adicionadas a qualquer formulário em algumas linhas de código. Neste artigo, apresentarei alguns detalhes técnicos de sua implementação, além de recursos na interface que são fornecidos automaticamente ao usuário ao trabalhar com qualquer lista em qualquer formulário.

Criação


As listas no formulário em lsFusion são adicionadas pela instrução OBJECTS :
OBJECTS i = Item
Uma tabela será adicionada ao formulário, na qual todos os objetos da classe Item estarão contidos nas linhas. Você pode adicionar vários objetos a uma única lista. Por exemplo
OBJECTS (i = Item, s = Stock)
Nesse caso, a tabela mostrará todos os pares possíveis de objetos das classes Item e Estoque .

As colunas são adicionadas à lista com a instrução PROPERTIES :
PROPERTIES name(i), name(s), quantityOnHand(i, s)
Na tabela, podem ser adicionados como detalhes simples do objeto, bem como quaisquer expressões com agrupamentos, particionamentos, recursões e assim por diante.

Por padrão, a lista mostrará todos os objetos no banco de dados. Para limitá-los, você pode usar a instrução FILTERS :
FILTERS quantityOnHand(i, s) > 0
Na condição de filtro, você pode usar qualquer expressão que dependa de objetos no formulário.

Navegação


Quando o usuário abre o formulário, a plataforma determina automaticamente o número de registros visíveis, dependendo do tamanho da tabela. Para simplificar a apresentação, presumimos que existam 50 registros assim. A cada momento, a plataforma armazena 150 registros no cliente e no servidor. Nesse caso, o objeto ativo atual deve estar no meio dessa “janela”: do 50º ao 99º registro. Pode haver menos entradas se o objeto atual estiver no início ou no final da lista.

Se você precisar ativar um registro específico ao abrir o formulário, serão feitas duas solicitações ao servidor de banco de dados, cada uma com 75 registros em cada lado do registro desejado. Em seguida, uma lista geral é colada a partir de seus resultados. No caso em que você precisa inicializar a lista do começo ou do fim, é feita uma solicitação para 100 registros e o primeiro ou o último registro recebido é ativado. O mesmo acontece se o usuário pressionar CTRL + HOME ou CTRL + END na lista para ir para o início ou o final da lista.

Assim que o usuário faz uma gravação ativa fora do meio da janela atual (antes da 50ª ou após a 99ª), a plataforma lê registros adicionais para que o registro atual esteja no "centro" da nova janela.

A peculiaridade de uma implementação de lista dinâmica é que o objeto atual não pode estar fora do meio da janela. Portanto, ao rolar a lista, o objeto atual é automaticamente movido para a área visível.
imagem


A leitura de dados em uma lista sempre ocorre em duas consultas. A primeira consulta lê apenas as chaves dos registros necessários na tabela temporária. A segunda consulta lê os valores de todas as colunas para as chaves já lidas. Isso é feito pelo motivo das colunas poderem conter quaisquer expressões que possam ser compiladas em subconsultas ou outras construções SQL complexas. Nesse caso, a própria plataforma envia essas chaves para subconsultas, para que o cálculo dos valores dessas colunas não atravesse todo o banco de dados, mas apenas de acordo com as chaves necessárias. Isso cria uma pequena sobrecarga, uma vez que são feitas duas consultas em vez de uma, mas protege contra a invasão acidental de um plano ineficiente de servidor de banco de dados.

Filtragem


As entradas na lista do formulário podem ser filtradas com base nas seguintes opções:

  • Indicação no código de seleção contínua usando a instrução FILTERS:
    FILTERS <>
    A expressão pode depender de quaisquer outros objetos atualmente selecionados no formulário. Por exemplo, se houver uma tabela ou uma árvore com um armazém no formulário, na expressão da lista de mercadorias, você pode consultar o armazém atual para filtrar apenas as mercadorias que estão na balança.
  • Indicação no código de seleção, que pode ser aplicado pelo usuário conforme necessário, usando a instrução FILTERGROUP :
    FILTERGROUP myFilters
    FILTER 'Filter 1' <expression> 'F5' DEFAULT
    FILTER 'Filter 2' <expression> 'F6'

    Uma lista suspensa será adicionada ao formulário (ou uma caixa de seleção se houver um filtro no grupo), com o qual o usuário poderá selecionar um dos filtros que precisa ser aplicado.
    imagem
  • Filtragem personalizada manualmente feita pelo usuário na interface:
    imagem
    Se a coluna da lista não for editável, ao inserir caracteres, o filtro dessa coluna será ativado automaticamente, o que pode ser redefinido com um simples toque na tecla ESC.

A própria plataforma monitora as alterações em quaisquer condições que possam afetar o filtro atual (alteração de objetos dependentes, ações do usuário etc.). Quando tais alterações são detectadas, a lista é atualizada automaticamente sem alterar o objeto atualmente selecionado. Para isso, são feitas duas solicitações, 75 entradas em cada direção a partir da atual e também durante a inicialização do formulário.

Classificação


Por padrão, as entradas nas listas são classificadas em ordem crescente dos identificadores internos dos objetos. Esses identificadores são gerados automaticamente em ordem crescente ao criar objetos (ao mesmo tempo, são globalmente exclusivos em todas as classes) e os índices são sempre criados sobre eles.

A classificação na lista pode ser alterada da seguinte maneira:

  • Indicando no código as colunas pelas quais a classificação é realizada através da instrução ORDER :
    ORDER column1(o) DESC , column2(o)
  • Clique duas vezes no cabeçalho da coluna pelo usuário (pressionar CTRL adicionará a classificação "aninhada").
    imagem

Dependendo da classificação atual, ao ler as chaves de registro, as expressões de coluna correspondentes serão adicionadas ao bloco ORDER BY da solicitação. Ao mesmo tempo, o identificador exclusivo do (s) objeto (s) é sempre adicionado à classificação para garantir que as chaves de todos os registros sejam exclusivas.

Uma expressão do formulário: coluna1> valor1 OR (coluna1 = valor1 AND coluna2> valor2) OR (coluna1 = valor1 AND coluna2 = valor2 AND chave> valor) será adicionada à cláusula WHERE da solicitação. Além disso, ao ler as teclas, a instrução LIMIT com o número necessário de registros legíveis será adicionada à solicitação. Ao ler os registros "para cima", a ordem em ORDER BY e a expressão WHERE serão "invertidas" de acordo para ler os registros na direção oposta.

Deve-se observar que a complexidade de executar essas consultas será relativamente pequena se houver um índice apropriado (já que o índice será a milhagem a partir da chave atual para cima ou para baixo apenas para um determinado número de registros). Portanto, para acelerar o trabalho com a lista dinâmica ao classificar pelas colunas column1, column2, é recomendável criar o seguinte índice:
INDEX column1(Object o), column2(o), o;
Se a classificação se basear na coluna calculada, ela poderá ser armazenada permanentemente, conforme descrito neste artigo , e então poderá ser criado um índice.

Um dos recursos dessa implementação é a falta de uma barra de rolagem "honesta". Ao ler registros, apenas o número necessário deles é lido. Uma solicitação para obter o número total de linhas na lista via COUNT (*) com o filtro desejado pode levar a uma execução completa na tabela ou no índice, o que afetará negativamente o desempenho. O mesmo problema ocorrerá ao ler registros através da construção OFFSET. Além disso, deve-se ter em mente que, ao navegar em uma lista, o número de entradas nela pode ser alterado por outros usuários, fazendo novas alterações.

Edição


Surpreendentemente, em algumas plataformas comerciais, eles não conseguiram perceber a capacidade de editar em listas dinâmicas. A principal dificuldade na implementação desse mecanismo é que apenas a janela visível é armazenada no servidor e no cliente, e as alterações podem ser feitas em toda a lista.

Não há mecanismo específico no lsFusion que implemente a edição de lista diretamente. Essa funcionalidade é implementada como parte do mecanismo da sessão geral.

Todas as alterações feitas na sessão de alteração atual são armazenadas em tabelas temporárias. Quando o usuário edita algo no formulário (incluindo o valor em uma das entradas), os novos valores são gravados em tabelas temporárias com as chaves apropriadas. Então, quando a segunda consulta (depois de receber as chaves) lê os valores das colunas, o JOIN com as tabelas temporárias correspondentes com alterações é simplesmente adicionado à consulta.

Ao salvar a sessão de alteração, é executada uma consulta, que em uma transação grava todos os valores das tabelas temporárias no banco de dados.

Ajuste de grupo


Frequentemente, o usuário precisa alterar o valor da coluna para todos os objetos selecionados na lista de uma só vez. Para fazer isso, há um botão especial na barra de ferramentas de cada lista (com a tecla de atalho F12). Quando pressionado, o modo normal de edição de células é ativado, mas as alterações são aplicadas não ao registro atual, mas a todos os selecionados.

Esse mecanismo permite editar rapidamente um grande número de objetos de acordo com os critérios especificados:
imagem


Assim como durante a edição normal, as alterações não são salvas imediatamente no banco de dados, mas são registradas em tabelas temporárias. Em seguida, o usuário precisará clicar no botão Salvar para gravá-los no banco de dados. A desvantagem dessa abordagem pode ser que o usuário acidentalmente altere os dados extras. Mas aqui, como dizem, o princípio funciona: "com grande poder vem grande responsabilidade".

Resumo da lista


Em qualquer lista, o usuário tem a oportunidade de descobrir o número de registros ou o valor de uma determinada coluna na seleção atual. Para fazer isso, o usuário precisa clicar nos botões apropriados na barra de ferramentas de uma lista específica:
imagem


Para obter esses dados, uma solicitação será gerada automaticamente com a expressão COUNT (*) ou SUM, em WHERE da qual a expressão de seleção atual será adicionada. Com esse recurso, você pode obter rapidamente totais de listas sem recorrer à geração de relatórios.

Na versão desktop do cliente, também é possível calcular a soma das células selecionadas por analogia com o Excel:
imagem


Copiar / colar


Na versão desktop, o usuário tem a oportunidade de marcar determinadas células, pressionar CTRL + C e colar os valores delas na área de transferência:
imagem


Da mesma maneira, você pode colar a tabela da área de transferência em qualquer lista editável em qualquer forma:
imagem

Essa oportunidade costuma ser uma alternativa ao desenvolvimento de importações especializadas.

Configuração da tabela


Em qualquer lista, você pode alterar alguns de seus parâmetros:
imagem

Você pode alterar a composição das colunas, seus tamanhos, títulos, máscaras e assim por diante. Você pode salvar as configurações da tabela para o usuário atual e para todos os usuários (se o usuário atual tiver os direitos necessários).

Observe a opção Tamanho da página. Usando-o, você pode redimensionar a “janela” descrita no início do artigo. Por exemplo, em vez de 50 entradas automáticas, você pode especificar um valor maior. Em seguida, uma quantidade maior de dados será baixada para o cliente e o servidor, mas as solicitações ocorrerão com menos frequência. Definir o valor desse parâmetro como 0 tornará normal a partir de qualquer lista dinâmica, ou seja, todas as entradas na lista serão sempre lidas. O tamanho da janela também pode ser especificado diretamente no código usando o parâmetro pageSize da instrução DESIGN .

Exportar para Excel


Para qualquer lista, é possível carregar todos os seus registros no Excel. Para fazer isso, basta clicar no seguinte botão:
imagem

Isso leva em consideração as seleções, classificações e apenas as colunas visíveis especificadas nas configurações da tabela.

Pivotante


Por padrão, qualquer lista é exibida como uma tabela. Mas existe a possibilidade de alternar para um modo de exibição especial, no qual o usuário pode criar vários relatórios e diagramas:
imagem


Com um pequeno número de entradas na lista, os dados serão processados ​​diretamente no cliente. Assim que a quantidade de dados exceder um determinado limite, as consultas do banco de dados geradas automaticamente no servidor serão usadas para agrupar os dados.

Alternativa


Uma pergunta razoável surge. Como resolver o problema de editar listas dinâmicas em plataformas nas quais esse recurso não é suportado. Na maioria das vezes, eles fazem uma lista simples, forçando o usuário a limitar o número de entradas por algumas seleções (por exemplo, especifique filtros por categoria, fornecedor ou outros diretórios relacionados).

No entanto, essa abordagem tem um problema sério. Mesmo com seleções estabelecidas, não há garantia de que um número significativo de registros não esteja na amostra. É impossível calcular antecipadamente o número de valores obtidos, pois muitas vezes a complexidade dessa operação é diretamente comparável à complexidade da obtenção de todos os dados. Assim, em alguns casos, um grande número de entradas será adicionado à lista, o que levará a um grande consumo de recursos no servidor ou cliente, bem como a uma redução significativa no desempenho.

Conclusão


A implementação de uma lista dinâmica no desenvolvimento moderno não é a tarefa mais trivial, pois as partes do cliente e do servidor estão envolvidas. Existem várias bibliotecas de código aberto com uma licença aberta no mundo que permitem implementar rápida e convenientemente essa funcionalidade.

Na plataforma aberta e gratuita da lsFusion, as listas dinâmicas são criadas em várias linhas de código e fornecem ao usuário um grande número de oportunidades para trabalhar com elas. Em combinação com a capacidade de editar essas listas, a plataforma permite que você trabalhe rapidamente com documentos em centenas de milhares de linhas, organize trabalhos convenientes na seleção de registros em documentos, realize alterações de grupos em diretórios e muito mais.

O uso de listas dinâmicas pode reduzir significativamente o consumo de tempo e memória do processador no servidor e no cliente, trabalhando com um conjunto limitado de dados, além de reduzir a carga no canal de comunicação entre o servidor e o cliente. Devido a essa alta eficiência, cinco das oito maiores redes de varejo realizam suas principais atividades operacionais em soluções baseadas na plataforma lsFusion na Bielorrússia.

Source: https://habr.com/ru/post/pt484648/


All Articles