Otimização cliente/servidor
4D fornece otimizações para solicitações ORDA que usam seleções de entidades ou carregam entidades em arquiteturas cliente/servidor. Essas otimizações aceleram a execução de seu aplicativo 4D ao reduzir drasticamente o volume de informações transmitidas pela rede. Estes incluem:
- o contexto de otimização
- o Cache ORDA
Arquiteturas suportadas
As arquiteturas cliente/servidor de ORDA que suportam a otimização são:
- Os datastores servidor acessados pelas aplicações 4D remotas através de
ds, - Dastores remotos, acessado via
Open datastore(solicitações clientes REST).
Contexto de otimização
O contexto de otimização é baseado nas seguintes implementações:
-
Quando um cliente solicita uma seleção de entidade do servidor, 4D "aprende" automaticamente quais atributos da seleção de entidade são realmente usados no lado do cliente durante a execução do código e constrói um "contexto de otimização" correspondente. Esse contexto é anexado à seleção da entidade e armazena os atributos usados. Será atualizado dinamicamente se outros atributos forem usados depois. Os seguintes métodos e funções accionam a fase de aprendizagem:
-
As solicitações subsequentes enviadas ao servidor sobre a mesma seleção de entidade reutilizam automaticamente o contexto de otimização e obtêm apenas os atributos necessários do servidor, o que acelera o processamento. Por exemplo, em um list box entity selection, a fase de aprendizagem ocorre durante a exibição da primeira linha. a visualização das linhas seguintes é optimizada. As funções a seguir associam automaticamente o contexto de otimização da seleção da entidade de origem à seleção da entidade retornada:
-
Um contexto de otimização existente pode ser passado como uma propriedade para outra seleção de entidade das mesmas dataclass, Desta forma, ignorando a fase de aprendizagem e acelerando a aplicação (veja Reutilizando a propriedade de contexto abaixo).
-
Você pode criar contextos de otimização manualmente usando a função
dataStore.setRemoteContextInfo()(veja contextos preconfigurando).

Contextos tratados em conexões estabelecidas através de Open datastore só podem ser usadas entre versões principais similares de 4D. Por exemplo, uma aplicação remota 4D 20.x pode usar apenas contextos de um servidor 4D Server 20.x datastore.
Exemplo
Dado o seguinte código:
$sel:=$ds. Employee.query("firstname = ab@")
For each($e;$sel)
$s:=$e.firstname+" "+$e.lastname+" works for "+$e.employer.name // $e.employer refers to Company table
End for each
Graças à otimização, esta solicitação receberá apenas dados de atributos usados (firstname, lastname, employer, employer.name) em $sel da segunda iteração do laço.
Reutilizando a propriedade context
Você pode aumentar os benefícios da otimização usando a propriedade context. Essa propriedade faz referência a um contexto de otimização "aprendido" para uma seleção de entidade. Ele pode ser passado como parâmetro para funções ORDA que retornam novas seleções de entidades, de modo que as seleções de entidades solicitem diretamente os atributos usados ao servidor e ignorem a fase de aprendizado.
Você também pode criar contextos usando a função
.setRemoteContextInfo().
A mesma propriedade de contexto de otimização pode ser passada para um número ilimitado de seleções de entidades na mesma classe de dados. Todas as funções ORDA que manipulam seleções de entidades suportam a propriedade context (por exemplo, dataClass.query() ou dataClass.all()). No entanto, lembre-se de que um contexto é atualizado automaticamente quando novos atributos são usados em outras partes do código. A reutilização do mesmo contexto em códigos diferentes pode resultar em sobrecarga do contexto e, portanto, reduzir sua eficiência.
Um mecanismo semelhante é implementado para as entidades que são carregadas, de modo que apenas atributos usados são requisitados (veja a função
dataClass.get()).
Exemplo com dataClass.query():
var $sel1; $sel2; $sel3; $sel4; $querysettings; $querysettings2 : Object
var $data : Collection
$querysettings:=New object("context";"shortList")
$querysettings2:=New object("context";"longList")
$sel1:=ds.Employee.query("lastname = S@";$querysettings)
$data:=extractData($sel1) // No método extractData uma otimização é acionada
// e associada ao contexto "shortList"
$sel2:=ds.Employee.query("lastname = Sm@";$querysettings)
$data:=extractData($sel2) // No método extractData a otimização associada a
// ao contexto "shortList" é aplicada
$sel3:=ds.Employee.query("lastname = Smith";$querysettings2)
$data:=extractDetailedData($sel3) // No método extractDetailedData uma otimização
// é acionada e associada ao contexto "longList"
$sel4:=ds.Employee.query("lastname = Brown";$querysettings2)
$data:=extractDetailedData($sel4) // No método extractDetailedData a otimização
// associada ao contexto "longList" é aplicada
List box baseado em uma seleção de entidades
A otimização da seleção de entidades é aplicada automaticamente a list boxes baseados na seleção de entidades em aplicativos de desktop cliente/servidor 4D, ao exibir e rolar o conteúdo de um list box: somente os atributos exibidos no list box são solicitados do servidor.
Um contexto "modo de página" específico também é fornecido ao carregar a entidade atual através da expressão da propriedade item atual da caixa de lista (veja Caixas de lista de seleção de coleções ou entidades). Esse recurso permite que você não sobrecarregue o contexto inicial da caixa de lista neste caso, especialmente se a "página" solicitar atributos adicionais. Observe que apenas o uso da expressão do item atual irá criar/usar o contexto da página (acesso através de entitySeletion\[index] irá alterar o contexto de seleção da entidade).
As solicitações subsequentes ao servidor enviadas pelas funções de navegação da entidade também darão suporte a essa otimização. As funções a seguir associam automaticamente o contexto de otimização da entidade de origem à entidade retornada:
Por exemplo, o código a seguir carrega a entidade selecionada e permite a navegação na seleção da entidade. As entidades são carregadas em um contexto separado e o contexto inicial da caixa de listagem não é alterado:
$myEntity:=Form.currentElement //expressão do item atual
//... fazer algo
$myEntity:=$myEntity.next() //carrega a próxima entidade usando o mesmo contexto
Pré-configuração de contextos
Um contexto de otimização deve ser definido para cada recurso ou algoritmo do seu aplicativo, a fim de obter os melhores desempenhos. Por exemplo, um contexto pode ser usado para consultas sobre clientes, outro contexto para consultas sobre produtos, etc.
Se quiser fornecer aplicativos finais com o mais alto nível de otimização, você pode pré-configurar seus contextos e, assim, economizar fases de aprendizado, seguindo estas etapas:
- Projete seus algoritmos.
- Execute seu aplicativo e deixe que o mecanismo de aprendizado automático preencha os contextos de otimização.
- Chame a função
dataStore.getRemoteContextInfo()oudataStore.getAllRemoteContexts()para coletar contextos. Você pode usar as funçõesentitySelection.getRemoteContextAttributes()eentity.getRemoteContextAttributes()para analisar como seus algoritmos usam atributos. - Na etapa final, chame a função
dataStore.setRemoteContextInfo()para construir contextos na inicialização da aplicação e usá-los em seus algoritmos.
Cache ORDA
Por motivos de otimização, os dados solicitados do servidor por meio do ORDA são carregados no cache remoto do ORDA (que é diferente do cache 4D). O cache do ORDA é organizado por classe de dados e expira após 30 segundos.
Os dados contidos no cache são considerados expirados quando o tempo limite é atingido. Qualquer acesso a dados expirados enviará um pedido ao servidor. Os dados expirados permanecem na cache até que seja necessário espaço.
Você pode forçar os dados de seleção de entidades no cache ORDA a expirar a qualquer momento usando a função refresh().
Por padrão, o cache ORDA é tratado de forma transparente pelo 4D. No entanto, você pode controlar seu conteúdo usando as seguintes funções da classe ORDA:
Using the local keyword
By default, ORDA data model functions are executed on the server, which usually provides the best performance since only the function request and the result are sent over the network. However, it could happen that a function processes data that's already in the local cache and is fully executable on the client side. In this case, you can save requests to the server and thus, enhance the application performance by using the local keyword in the function definition.
Note-se que a função funcionará mesmo que eventualmente seja necessário aceder ao servidor (por exemplo, se a cache ORDA tiver expirado). No entanto, é altamente recomendável certificar-se de que a função local não acede a dados no servidor, caso contrário a execução local não poderá trazer qualquer benefício em termos de desempenho. Uma função local que gera muitos pedidos ao servidor é menos eficiente do que uma função executada no servidor que apenas devolveria os valores resultantes. Por exemplo, considere a seguinte função na classe de entidade Escolas:
// Get the youngest students
// Inappropriate use of local keyword
local Function getYoungest() : Object
return This.students.query("birthDate >= :1"; !2000-01-01!).orderBy("birthDate desc").slice(0; 5)
- sem a palavra-chave
local, o resultado é dado através de um único pedido - com a palavra-chave
local, 4 pedidos são necessários: um para obter os alunos da entidade das escolas, um para aquery(), um para oorderBy(), e um para oslice(). Neste exemplo, usar a palavra-chavelocalé inapropriado.
Example: Checking attributes
Pretendemos verificar a consistência dos atributos de uma entidade carregada no cliente e actualizada pelo utilizador antes de solicitar ao servidor que os guarde.
Na classe AlunosEntidade, a função local checkData() verifica a idade do Aluno:
Class extends Entity
local Function checkData() -> $status : Object
$status:=New object("success"; True)
Case of
: (This.age()=Null)
$status.success:=False
$status.statusText:="The birthdate is missing"
:((This.age() <15) | (This.age()>30) )
$status.success:=False
$status.statusText:="The student must be between 15 and 30 - This one is "+String(This.age())
End case
Código de chamada:
var $status : Object
//Form.student is loaded with all its attributes and updated on a Form
$status:=Form.student.checkData()
If ($status.success)
$status:=Form.student.save() // call the server End if