Cache local
Funcionamento do cache local na plataforma Nginstack, incluindo manipulação de DataSets, operações no banco de dados e uso do cache local.
O conceito de Classe de Dados e Hierarquia de Classe será melhor compreendido através de um exemplo.
Pense em Classe de Dados como o campo TIPO de uma tabela chamada ENTIDADE, onde o tipo pode ser: PESSOA_FISICA, PESSOA_JURIDICA, CLIENTE, FORNECEDOR, VENDEDOR, FUNCIONARIO etc. Graficamente seria algo assim:

Note que entre os possíveis valores para o campo TIPO há intuitivamente uma hierarquia. Veja:

O conceito de Classe de dados do sistema é bem semelhante ao exemplo apresentado acima, só que o campo TIPO da tabela ENTIDADE se chama CLASSE.
Há no sistema, portanto, uma tabela chamada CLASSE que armazena todas as Classe de Dados. A tabela CLASSE é referenciada em todos as outras tabelas cadastrais por um campo chamado CLASSE ou iClass. Nesta tabela existe um campo chamado MAE que é usado para definir o relacionamento de hierarquia entre as Classes de Dados.
É comum desenvolvedores acharem estranho a seguinte afirmação: “Os registros no sistema são gravados em uma Classe de Dados”. Geralmente eles ficam se perguntando: “Mas os registros não são gravados em tabelas?”.
Bem, o fato é que as duas afirmações estão corretas. Logicamente o sistema grava registros em classes, mas fisicamente, estes registros são gravados em tabelas.
No exemplo hipotético, criaremos uma classe chamada Contatos que na hierarquia de classes será filha de Raiz\Dados\Cadastrais\Entidades\Pessoas. Para isso basta clicar com o botão direito na classe Pessoa e depois em Insert, na IDE do Engine.
Após clicar Insert, aparecerá uma nova classe chamada Nova Classe <Chave da Classe> a qual o desenvolvedor poderá renomear para Contatos. Como a classe contatos é filha da classe Pessoas ela herda os campos definidos em Pessoas e inclusive o desenvolvedor já poderá ver se há registros na classe Contatos.
Veja que a tabela onde ficam os registros da Classe de Dados Contatos é a tabela ENTIDADE.
Neste ponto você pode estar se perguntando: Como é possível saber qual o nome da tabela que guarda os registro de uma classe que criamos?
Bem, para responder este questionamento é necessário introduzir o conceito de x-class e x-model.
Atenção: Os arquivos do tipo x-class são deprecated e não devem ser mais utilizados, prefira utilizar x-model e x-view.
Os X-Classes no sistema são arquivos do tipo application/x-class que possuem a extensão “.ic”. São usados basicamente para configurar o software e definir telas de processo do Framework HTML.
No X-Class são definidos, por exemplo:
Como podemos usar o X-Class para configurar a tabela que irá guardar os registros de uma classe? Bem, basta criar um arquivo X-Class dentro da classe em questão e colocar no nome da tabela na propriedade this.tableName. O this no contexto do x-class se refere à própria classe.
Mais de um x-class pode ser definido para uma classe, e a ordem lexicográfica deles importa. Arquivos anteriores podem ter configurações sobrescritas por arquivos posteriores.
Configurações definidas em x-class para classes mãe são herdadas pelas classes filhas.
Arquivos x-model são do tipo de arquivo application/x-model e possuem a extensão “.model”. Contém as definições do esquema de uma tabela representada por uma classe, seguindo o conceito de ORM (Object Relational Mapping). Essas definições são responsáveis pela estrutura de tabelas, configurações de campos e regras de negócio que independem da interface.
Existe a divisão de definições e portanto tudo que diz respeito a esquema de tabelas do banco de dados deve estar somente no arquivo x-model.
Como poderemos usar os arquivos de definição para configurar uma tabela que irá guardar os registros de uma classe?
Para isso é necessário criarmos um arquivo x-model dentro da classe em questão e colocar no nome da tabela na propriedade this.tableName.
Deve ser definido também a propriedade this.lookupDisplayFieldName. Apesar do nome dessa propriedade remeter uma definição visual, ela trata o valor que será derivado do registro de uma tabela, ou seja, qualquer consulta utilizando as definições de classe sobre o dado de uma classe A que possui lookup para outra classe B irá retornar o valor do campo de mesmo nome que estiver definido em this.lookupDisplayField para o mesmo registro da tabela da classe B.
Uma prática que deve ser adotada é o uso de Resource Strings na propriedade help, tendo como principal objetivo melhorar o uso da memória, uma vez que a informação só é carregada quando for necessária.
Assim como no x-class, uma configuração definida em um arquivo x-model pode ser sobrescrita por outro x-model que vier depois na ordem lexicográfica.
Para exemplificar este sistema de prioridades dos arquivos, suponhamos que existam os seguintes arquivos numa classe do sistema:
0100 Engine.model 0150 Engine.model 0200 Engine.model
O caso acima mostra que as configurações que forem definidas no arquivo 0200 Engine.model irão sobrescrever as configurações definidas no arquivo 0150 Engine.model, que por sua vez, também sobrescreverão o arquivo 0100 Engine.model. Isso também acontece na hierarquia de classes, ou seja, as definições nas classes filhas sobrescrevem as configurações da classe mãe.
Abaixo está definido o padrão numérico utilizado para os intervalos por tipo de arquivo:
Obs: Entende-se por produto custom chaves positivas também.
Abaixo temos um trecho de um arquivo x-model como exemplo:
__includeOnce(-1898144572) /* NetworkUtilities.ijs */
// Definição do nome da tabela que irá guardar os registros da classe Engines e das suas filhas.
this.tableName = 'iHost';
this.upgradeChangesTableStructure = true;
this.cachedData = true;
this.lookupDisplayFieldName = 'iName';
this.on('lookupDisplay', function (evt){
evt.displayValue = evt.key ? DBKey.from(evt.key).str('iName') : '';
})
// Definição do campo iKey
let fld = this.field('iKey', 'integer');
fld.label = 'Chave';
fld.required = true;
fld.readOnly = true;
fld.order = -1000;
fld.help = $R(-1898140920);
// Definição do campo iClass
fld = this.field('iClass', 'integer');
fld.label = 'Classe';
fld.required = true;
fld.order = 20;
fld.classKey = this.key;
fld.lookupType = LookupType.CLASS;
fld.help = $R(-1898140918);
// Definição do campo iIPAddresses
// Eventos responsáveis pela manipulação e validação dos dados pertencem ao model.
let fld = this.field('iIPAddresses', 'string', 100);
fld.label = 'Endereços IP';
fld.required = true;
fld.order = 50;
fld.on('beforeChange', function (evt){
const value = evt.newValue;
if (value) {
const ar = value.split(",");
for (let i = 0; i < ar.length; ++i){
if (ar[i] == 'dhcp' || NetworkUtilities.isIPv4Address(ar[i])){
ar[i] = ar[i].trim();
} else {
throw new Error("O valor \"" + ar[i] + "\" não é um endereço IP válido.");
}
}
evt.newValue = ar.join(',');
}
});
fld.help = $R(-1898140912);
fld = this.field('xServices', 'masterdetail');
fld.order = 500;
fld.label = 'Serviços';
fld.classKey = -1898146242; /* Services */
fld.masterFieldNames = 'iKey';
fld.detailFieldNames = 'iServer';
fld.help = $R(-1898140898);
Arquivos x-view são do tipo de arquivo application/x-view, possuem a extensão “.view” e são usados para definir a interface com o usuário. Nele temos:
Obs: Os arquivos x-view definem uma interface para visualização dos dados. É importante ressaltar que NÃO devem ser inseridas regras de negócio no x-view.
Para exemplificar o uso do arquivo x-view, segue abaixo um arquivo x-view:
this.lookupTableViewWidth = 20;
let fld = this.field('iKey');
fld.visible = false
fld = this.field('iClass');
fld.tableViewWidth = 10;
fld = this.field('iIPAddresses');
fld.tableViewWidth = 20;
fld = this.field('iServices');
fld.detailIndexFieldNames = 'iName';
fld.on('defineGrid', function (evt){
const grid = evt.field.grid;
grid.on('defineFields', function (evt){
let fld = evt.grid.field("iHost");
fld.visible = false;
});
grid.on('afterInsert', function (evt){
const ds = evt.grid.ds;
const masterGrid = evt.grid.parent.parent;
ds.iserver = masterGrid.ds.ikey;
});
})
Funcionamento do cache local na plataforma Nginstack, incluindo manipulação de DataSets, operações no banco de dados e uso do cache local.
Procedimentos para migração de bases de dados para o uso de chaves e versões de 64 bits.