Histórico da Página
Informações | ||
---|---|---|
| ||
Este recurso está disponível a partir da atualização 1.5.5 do TOTVS Fluig Plataforma. |
...
Índice | ||||||
---|---|---|---|---|---|---|
|
Conceito
|
Nota | ||
---|---|---|
| ||
A partir das atualizações 1.6.5 Liquid, 1.7.0 Lake e 1.7.1 Crystal Lake, os select passados por constraint em dataset serão bloqueados pelo serviço. Orientamos a leitura da documentação Datasets acessando banco de dados externo que contém um exemplo da correta utilização do procedimento. |
Conceito
...
A sincronização de datasets tem como objetivo reduzir o número de acessos a serviços de dados fornecidos por produtos externos à plataforma TOTVS Fluig. É uma prática comum trazer dados de sistemas externos para complementar informações do formulário de um processo ou realizar validações em eventos com base nas informações retornadas por este dataset.
Exemplificando
Em um exemplo mais específico, vamos supor que o usuário precisa informar no formulário de seu processo A sincronização de datasets tem como objetivo reduzir o número de acessos a serviços de dados fornecidos por produtos externos ao Fluig. É uma prática comum trazer dados de sistemas externos para complementar informações do formulário de um processo ou realizar validações em eventos com base nas informações retornadas por este dataset. Em um exemplo mais específico vamos supor que o usuário precisa informar no formulário de seu processo o centro de custo e que a lista dos centros de custo válidos está disponível em um sistema externo. Para que este usuário consiga informar um centro de custo válido ele deverá , será necessário:
- o usuário acessar o campo com pesquisas, através de um formulário
...
- ;
- esse campo solicita informações para o dataset
...
- ;
- o dataset, quando executado através
...
- da plataforma, faz acesso ao serviço de dados do sistema externo.
Se este workflow possuir uma média de cinco mil abertura aberturas de processo por dia, teremos pelo menos cinco mil acessos a este sistema externo que, em muitos casos, acaba retornando sempre as mesmas informações ou tendo uma variação muito pequena de informações entre uma consulta e outra.
O desenho abaixo ilustra como funciona o ciclo de acesso do usuário a uma informação externa ao fluigà plataforma.
Figura 1 - Ciclo de acesso do usuário a uma informação externa à plataforma
Contudo, como tratatratam-se de sistemas sistemas externos não é possível para o fluig garantir tanto a performance quanto a disponibilidade desses serviços de dados. Em eventuais de Eventuais problemas de performance ou disponibilidade impactarão o desempenho do fluig da plataforma TOTVS Fluig e podem até mesmo inviabilizar o uso de determinado processo workflow como um todo.
Sincronização de Datasets
...
No modelo de dados sincronizados o fluig através , por meio de uma tarefa agendada realiza é possível realizar a consulta do sistema externo e copia os dados retornados para uma tabela espelho criada dentro do banco de dados do fluigda plataforma.
Figura 2 - Tarefa agendada para consulta ao sistema externo
Uma vez que a primeira sincronização tenha sido concluída com sucesso, todas as consultas realizadas neste dataset não irão mais consultar o sistema externo e , mas sim a tabela que foi espelhada pela tarefa agendada. Em nosso cenário hipotético caso o administrador do sistema opte por agendar a tarefa que atualiza a lista de centros de custo uma vez por dia
O diagrama abaixo apresenta um modelo conceitual sobre os Datasets.
Nota |
---|
Para garantir um melhor desempenho na utilização de datasets consulte Constraints Avançadas e utilize o parâmetro sqlLimit. |
Tipos de Datasets
Atualmente existem três tipos de Datasets gerenciados pelo produto:
- Built-in Datasets: Este tipo de Dataset permite navegar em dados das entidades do próprio fluig, como usuários, grupos, processos ou tarefas por exemplo. Esses datasets são pré-definidos no produto e não podem ser alterados pelo usuário;
- CardIndex Datasets: Este tipo de Dataset permite navegar nos dados existentes em formulários de uma determinada definição de formulário publicada no fluig. Para que uma definição de formulário seja disponibilizada como Dataset, é necessário preencher o campo Nome Dataset na publicação da definição de formulário. O valor informado será utilizado para a busca do Dataset no fluig;
- Customized Dataset: Este tipo de Dataset permite navegar nos dados retornados por uma customização onde é possível definir as colunas do Dataset e os valores de cada um dos registros, através da codificação em JavaScript. Os Datasets customizados podem ser utilizados em uma grande gama de situações, como para definição de uma lista de valores fixos (como estados de um país) ou para extração de dados de um serviço externo (via WebServices, por exemplo).
Ainda que os Dataset possam ter origens distintas, não existe qualquer diferença sob a perspectiva do componente que fará uso deste Dataset. Isto significa, por exemplo, que se um determinado componente fizer uso de um Dataset chamado "centroCusto", o seu uso será exatamente o mesmo, independente deste Dataset ser pré-construído, baseado em definição de formulário ou customizado.
Esta característica dos Datasets representa um grande benefício para os usuários, uma vez que a fonte dos Datasets pode ser alterada sem que isto represente retrabalho nos pontos onde ele é utilizado.
Por exemplo, considere um processo workflow que precise trabalhar com uma lista de centros de custo. Em um primeiro momento, pode-se trabalhar com um Dataset customizado que monte, de forma fixa, os registros referentes a cada um dos centros de custo necessários para o usuário.
Uma vez que codificar a lista se torne pouco flexível (devido à alterações freqüentes), é possível trocar o centro de custo para que seja baseado em definição de formulário. Desde que se observe o nome dos campos do Dataset, não haverá qualquer impacto sobre o processo workflow.
Em um terceiro momento, pode-se optar por migrar o Dataset novamente para o tipo customizado, mas desta vez extraindo os centros de custo do ERP do cliente. Novamente não haverá impacto para o processo workflow (ou para os demais pontos que utilizem o Dataset), desde que se observe o nome dos campos.
Visualizando Datasets
Via fluig Studio
Pelo fluig Studio, através da visão Visualização de Dataset, é possível consultar os Datasets disponíveis bem como visualizar o seu conteúdo. Com isto é possível verificar quais os campos disponíveis, tanto para filtros quanto para acesso, bem como fazer testes sobre Datasets customizados.
O exemplo abaixo apresenta um exemplo de Dataset sendo visualizado:
Neste exemplo, é possível visualizar os campos disponíveis (conta, titulo, natureza e tipo) e os registros retornados pelo Dataset. Note que estas informações são essenciais para o uso dos Datasets, principalmente quando há necessidade de restringir os dados que queremos acessar.
Via Widget
Pelo fluig, através da widget Listar registros de datasets, é possível consultar os Datasets disponíveis bem como visualizar o seu conteúdo. Com isto é possível verificar quais os campos disponíveis, tanto para filtros quanto para acesso. Através desta widget, datasets podem ser publicados em páginas ou comunidades.
O exemplo abaixo apresenta um exemplo de Dataset sendo visualizado pela widget:
Filtro em Datasets - Widget
Para filtrar os dados na widget de visualidação de Datasets, é necessário selecionar quais os campos que você deseja utilizar o filtro, conforme a imagem a seguir:
Nota |
---|
Observação¹: Em Built-in Datasets ou CardIndex Datasets o filtro por campos metadata funcionarão apenas se forem únicos, ou seja, se deseja filtrar por "metadata#parent_id", o filtro deve estar ativado apenas para ele. Observação²: Em Datasets customizados, a busca deve ser implementada junto ao seu código de criação. |
Acessando um Dataset
Vários pontos do fluig podem fazer uso dos Datasets. Dependendo do local onde o Dataset é utilizado, podem ocorrer variações na forma de acessá-lo ou de manuseá-lo.
Via pontos de customização
Quando um Dataset é acessado via um ponto de customização como eventos globais, eventos de processos, eventos de definição de formulário ou mesmo em outros Datasets, isto é feito através de chamadas JavaScript que serão executadas no lado servidor.
O exemplo abaixo apresenta um exemplo simples de chamada a um Dataset:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
function doTest1() {
var dataset = DatasetFactory.getDataset("group", null, null, null);
return dataset.rowsCount;
} |
No exemplo acima, o código JavaScript faz o acesso ao Dataset "group", que é um Dataset interno do sistema, e retorna a quantidade de linhas disponíveis (rowsCount). O objeto DatasetFactory é a "porta de entrada" para o acesso a qualquer Dataset. Além de permitir a carga de um Dataset, ela também permite navegar entre todos os Datasets disponíveis no sistema.
O acesso a um Dataset é feito através do método getDataset do objeto DatasetFactory, onde seus parâmetros são:
- Nome do Dataset: Nome do Dataset a ser buscado;
- Campos: Array com os campos do Dataset que serão retornados. Caso seja informado null, retorna todos os campos do Dataset;
- Constraints: Array com os condições de busca do Dataset. Caso seja informado null, retorna todos os registros do Dataset.
- Ordem: Array com os campos para ordenação dos registros do Dataset. Caso seja informado null, retorna os registros com a ordenação padrão.
Já para a criação das constraints é utilizado o método createConstraint do objeto DatasetFactory, onde seus parâmetros são:
- Campo: Nome do campo que será filtrado;
- Valor Inicial: Valor inicial da faixa de valores do filtro
- Valor Final: Valor final da faixa de valores do filtro
- Tipo: Tipo da condição, podendo ser:
- MUST: indica que todos os registros do Dataset devem satisfazer a esta condição.
- SHOULD: indica que os registros do Dataset podem ou não atender à condição. Esse tipo é mais comum quando se necessita que um mesmo campo tenha valores A ou B (onde cada um será uma condição de busca com tipo SHOULD).
- MUST_NOT: indica que nenhum dos registros pode satisfazer a condição.
Após a criação da constraint, é possível informar que esta será utilizada na consulta em formato de LIKE, ou seja, o valor retornado poderá conter qualquer letra ou sequência de letras no lugar do símbolo '%'. Isso é feito chamando o método setLikeSearch(true) para a constraint que se deseja este comportamento, conforme exemplificado na implementação abaixo, na constraint c5, onde pretende-se retornar todos os registros que NÃO possuam (pois é uma constraint MUST_NOT) a palavra "teste" na descrição do documento.
Exemplo:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
function doTest2() {
//Monta as constraints para consulta
var c1 = DatasetFactory.createConstraint("activeVersion", "true", "true", ConstraintType.MUST);
var c2 = DatasetFactory.createConstraint("publisherId", "adm", "adm", ConstraintType.MUST_NOT);
var c3 = DatasetFactory.createConstraint("documentType", "1", "1", ConstraintType.SHOULD);
var c4 = DatasetFactory.createConstraint("documentType", "2", "2", ConstraintType.SHOULD);
var c5 = DatasetFactory.createConstraint("documentDescription", "%teste%", "%teste%", ConstraintType.MUST_NOT);
c5.setLikeSearch(true);
var constraints = new Array(c1, c2, c3, c4, c5);
//Define os campos para ordenação
var sortingFields = new Array("documentPK.documentId");
//Busca o dataset
var dataset = DatasetFactory.getDataset("document", null, constraints, sortingFields);
for(var i = 0; i < dataset.rowsCount; i++) {
log.info(dataset.getValue(i, "documentPK.documentId"));
}
} |
Nota |
---|
O método setLikeSearch(true) está disponível a partir da versão 1.3.9 do fluig. Para utilizar a função likeSearch utilizando a biblioteca vcXMLRPC.js, deve ser adicionado mais um parâmetro no método DatasetFactory.createConstraint, e não utilizar o método setLikeSearch(true). Exemplo: var c5 = DatasetFactory.createConstraint("documentDescription", "%teste%", "%teste%", ConstraintType.MUST_NOT, true); Isto é válido apenas para a utilização da biblioteca vcXMLRPC.js. |
Constraints Avançadas
Existe uma constraint em especial que é utilizada para limitar o número de registros na consulta SQL chamada de sqlLimit. Então é possível definir o número máximo de registros que uma consulta SQL pode retornar, porém o número de registros pode ser menor que o esperado, devido algumas validações que são feitas após o retorno dos dados. Por exemplo: O sqlLimit tem um valor 100 e é feita uma consulta em um serviço de dados de uma definição de formulário, esta consulta retornará os 100 registros, porém após isso são executadas validações para verificar se o formulário está ativo e se o usuário corrente tem permissão para visualizar os dados fazendo com que o retorno possa ser menor que 100. Para o sqlLimit é utilizada a seguinte sintaxe:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
DatasetFactory.createConstraint("sqlLimit", "10", "10", ConstraintType.MUST); |
Nota |
---|
Observação: O valor considerado no sqlLimit é sempre o initialValue, o que for informado no finalValue não será considerado. |
Existe outra constraint especial utilizada somente para acesso a datasets de definições de formulário, ela indica se ao buscar o serviço de dados devem ser retornados APENAS os dados dos formulários da definição de formulário principal. A constraint é a onlyMainCards e por padrão seu valor é false, ou seja, são retornados os dados dos formulários da definição de formulário principal e das definições de formulários filhas.
Bloco de código |
---|
DatasetFactory.createConstraint("onlyMainCards", "true", "true", ConstraintType.MUST); |
Nota |
---|
Observação: O valor considerado no onlyMainCards é sempre o initialValue, o que for informado no finalValue não será considerado. |
Nota |
---|
Atenção: As constraints podem ser utilizadas apenas para datasets internos. Datasets customizados não aceitam constraints, pelo fato de os dados serem externos, não sendo possível aplicar o filtro em sua origem. Para Datasets customizados o tratamento de filtros deve ser feito na codificação do Dataset, manipulando o objeto retornado e retirando as informações desnecessárias. |
Exemplificação de uso de Constraints
Considere os valores da tabela abaixo sendo utilizadas como um serviço de dados a partir de uma definição de formulário para exemplificação dos exemplos:
Código | Nome | Cidade |
---|---|---|
1 | Javier Spiva | São Paulo |
2 | Cody Ballow | Rio de Janeiro |
3 | Javier Naramore | São Paulo |
4 | Max Nevius | Rio de Janeiro |
5 | Noemi Roiger | São Paulo |
6 | Lonnie Cadwallader | Rio de Janeiro |
7 | Lorrie Spece | Brasília |
Verifique os exemplos de retorno de dados abaixo:
Deck of Cards | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Via JavaScript em formulário
O fluig permite acessar os Datasets via código JavaScript no HTML de uma definição de formulário utilizando a biblioteca vcXMLRPC.js. Para isto, basta incluir a linha abaixo antes da tag body do HTML:
Bloco de código | ||||
---|---|---|---|---|
| ||||
<script type="text/javascript" src="../vcXMLRPC.js"></script> |
Nota |
---|
Importante: Este modelo de acesso faz com que o Dataset seja transportado do servidor para o cliente, ou seja, o navegador do usuário. Por isso, é importante observar a quantidade de informações que será manuseada, caso contrário pode-se ter problemas de consumo excessivo de banda ou performance. |
Exemplo:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
function showNewDatasetFull() {
var div = document.getElementById("datasetDiv");
//Busca o dataset
try {
var dataset = DatasetFactory.getDataset("colleague");
div.innerHTML = showDataset(dataset);
} catch(erro) {
div.innerHTML = erro;
}
}
function showDataset(dataset) {
var tabela = "<table>";
//Monta o cabeçalho
tabela += "<tr>";
for (var i = 0; i < dataset.columns.length; i++) {
tabela += "<th>" + dataset.columns[i] + "</th>";
}
tabela += "</tr>";
//Monta os registros
for (var x = 0; x < dataset.values.length; x++) {
tabela += "<tr>";
var row = dataset.values[x];
for (var y = 0; y < dataset.columns.length; y++) {
tabela += "<td>" + row[dataset.columns[y]] + "</td>";
}
tabela += "</tr>";
}
tabela += "</table>";
return tabela;
} |
No exemplo acima, percebe-se que a forma de se invocar um Dataset é semelhante ao método via pontos de customização, através do DatasetFactory. A função showDataset apresenta um exemplo de código que permite apresentar os dados do Dataset.
Assim como no método via pontos de customização, quando é preciso filtrar um Dataset é preciso criar as constraints que serão utilizadas na busca. Os argumentos utilizados no método getDataset também são os mesmos que apresentados anteriormente:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
function showNewDatasetPartial() {
var div = document.getElementById("datasetDiv");
var c1 = DatasetFactory.createConstraint("parentDocumentId", "5", "5", ConstraintType.MUST);
var c2 = DatasetFactory.createConstraint("documentType", "1", "1", ConstraintType.MUST_NOT);
var c3 = DatasetFactory.createConstraint("activeVersion", "true", "true", ConstraintType.MUST);
var constraints = new Array(c1, c2, c3);
//Define os campos para ordenação
var fields = new Array("documentPK.documentId", "documentDescription",
"documentType", "publisherId", "accessCount");
var sortingFields = new Array("accessCount", "documentDescription");
//Busca o dataset
try {
var dataset = DatasetFactory.getDataset("document", fields, constraints, sortingFields);
div.innerHTML = showDataset(dataset);
} catch(erro) {
div.innerHTML = erro;
}
} |
Via Tags no Formulário
O fluig permite especificar um Dataset em um campo select (combo-box). Quando isto é feito, as opções do combo são automaticamente criadas de acordo com os dados do Dataset. Para isso, é necessário adicionar três propriedades adicionais à tag:
Propriedade | Descrição |
---|---|
dataset | Determina o Dataset utilizado |
datasetkey | Determina qual coluna do Dataset será utilizada como valor do campo |
datasetvalue | Determina qual coluna do Dataset será utilizada como rótulo das opções do combo |
No exemplo abaixo, o campo "estado" foi configurado para que as opções do combo sejam criadas a partir do Dataset "estadosBR". Como valor do campo será utilizado o campo "Sigla", embora para o usuário será apresentado o campo "Estado".
Bloco de código | ||||
---|---|---|---|---|
| ||||
<select name="estado" dataset="estadosBR" datasetkey="Sigla" datasetvalue="Estado"></select> |
Via Web Services
O fluig disponibiliza um conjunto de WebServices que permitem integrar aplicações de terceiros ao produto. Dentre os serviços disponibilizados, o serviço ECMDatasetService permite fazer o acesso a um Dataset. Para verificar a lista de serviços disponíveis no fluig, acesso a URL http://<servidor>:<porta>/webdesk/services.
A forma de uso de um Web Service varia de acordo com a tecnologia utilizada pela aplicação cliente. Consulte a documentação da tecnologia escolhida pra obter detalhes sobre como acessar Web Services.
Construindo um Dataset Customizado
Um Dataset é construído a partir de um código JavaScript. Uma vez que o próprio Dataset é criado a partir de um código JavaScript, é possível fazer chamadas a outros Datasets, chamadas à serviços externos ou apenas criar o Dataset a partir de valores codificados.
Nota | ||
---|---|---|
| ||
Em datasets customizados é possível realizar chamadas para os serviços disponíveis na API pública. Acesse aqui nosso guia de consumo da API pública em eventos. |
No exemplo Abaixo é criado um Dataset cujo os campos e valores estão fixos no código:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
function createDataset(fields, constraints, sortFields) {
var dataset = DatasetBuilder.newDataset();
//Cria as colunas
dataset.addColumn("Sigla");
dataset.addColumn("Estado");
dataset.addColumn("Capital");
dataset.addColumn("Area");
//Cria os registros
dataset.addRow(new Array("AM", "Amazonas", "Manaus", 1570746));
dataset.addRow(new Array("PA", "Pará", "Belém", 1247690));
dataset.addRow(new Array("MT", "Mato Grosso", "Cuiabá", 903358));
dataset.addRow(new Array("TO", "Tocantins", "Palmas", 277621));
dataset.addRow(new Array("PI", "Piauí", "Teresina", 251529));
return dataset;
} |
Para criar um novo Dataset, é utilizado o método DatasetBuilder.newDataset(). A partir do objeto criado é possível adicionar as colunas desejadas (método addColumn) bem como adicionar linhas (método addRow).
Note que a função javascript createDataset, que cria o Dataset, recebe como parâmetros os campos, as constraints e a ordenação. Cabe ao desenvolvedor utilizar estes valores na lógica de implementação do Dataset customizado. Caso seja desconsiderado algum desdes campos, os filtros não serão aplicados. Os parâmetros "fields" e "sortFields" são arrays de String, que possuem, respectivamente, os nomes dos campos que serão retornados e os nomes dos campos utilizados para ordenação. Já o parâmetro "constraints" é um array de objetos do tipo Constraint, onde cada objeto deste array possui as seguintes propriedades:
Propriedade | Descrição |
---|---|
fieldName | Nome do campo |
initialValue | Valor inicial para filtro neste campo |
finalValue | Valor final para filtro neste campo |
contraintType | Tipo do filtro deste campo, podendo ter os valores abaixo: MUST: O valor informado precisa estar nos resultados SHOULD: O valor informado pode estar ou não nos resultados MUST_NOT: O valor informado não pode estar nos resultados |
Para acessar estas propriedades e analisar os valores de cada item, pode-se utilizar um laço de repetição, conforme implementação abaixo:
Bloco de código | ||||
---|---|---|---|---|
| ||||
function createDataset(fields, constraints, sortFields) {
var company;
var initialDate;
var finalDate;
if (constraints != null) {
for (var i = 0; i < constraints.length; i++) {
if (constraints[i].fieldName == "company") {
company = constraints[i].initialValue;
}
else if (constraints[i].fieldName == "date") {
initialDate = constraints[i].initialValue;
finalDate = constraints[i].finalValue;
}
}
}
.
.
.
} |
A partir da versão 1.4.10, também é possível obter o código da empresa e do usuário autenticado através do método getValue(), conforme exemplo abaixo:
Bloco de código | ||||
---|---|---|---|---|
| ||||
function createDataset(fields, constraints, sortFields) {
var companyId = getValue("WKCompany");
var currentUser = getValue("WKUser");
.
.
.
} |
Dataset customizado de definição de formulário "pai-filho"
Para acessar informações de um "pai-filho" de uma definição de formulário pode ser utilizado o WebService "ECMDatasetService" (do próprio fluig), um Dataset customizado (Exemplo 1), ou ainda um evento de processo ou definição de formulário (Exemplo 2).
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
function createDataset(fields, constraints, sortFields) {
//Cria as colunas
var dataset = DatasetBuilder.newDataset();
dataset.addColumn("NumFormulario");
dataset.addColumn("Id");
dataset.addColumn("Peca");
dataset.addColumn("Quantidade");
//Cria a constraint para buscar os formulários ativos
var cst = DatasetFactory.createConstraint("metadata#active", true, true, ConstraintType.MUST);
var constraints = new Array(cst);
var datasetPrincipal = DatasetFactory.getDataset("dsExemploPaiFilho", null, constraints, null);
for (var i = 0; i < datasetPrincipal.rowsCount; i++) {
var documentId = datasetPrincipal.getValue(i, "metadata#id");
var documentVersion = datasetPrincipal.getValue(i, "metadata#version");
//Cria as constraints para buscar os campos filhos, passando o tablename, número da formulário e versão
var c1 = DatasetFactory.createConstraint("tablename", "tabelaPecas" ,"tabelaPecas", ConstraintType.MUST);
var c2 = DatasetFactory.createConstraint("metadata#id", documentId, documentId, ConstraintType.MUST);
var c3 = DatasetFactory.createConstraint("metadata#version", documentVersion, documentVersion, ConstraintType.MUST);
var constraintsFilhos = new Array(c1, c2, c3);
//Busca o dataset
var datasetFilhos = DatasetFactory.getDataset("dsExemploPaiFilho", null, constraintsFilhos, null);
for (var j = 0; j < datasetFilhos.rowsCount; j++) {
//Adiciona os valores nas colunas respectivamente.
dataset.addRow(new Array(
documentId,
datasetFilhos.getValue(j, "wdk_sequence_id"),
datasetFilhos.getValue(j, "peca"),
datasetFilhos.getValue(j, "qtde")));
}
}
return dataset;
} |
dia. Após a sincronização a performance e a disponibilidade do sistema externo não afetarão mais a performance da plataforma e dos sistemas workflow.
Nota | ||
---|---|---|
| ||
A Sincronização de datasets em tabelas da plataforma não pode ser utilizada em datasets do tipo interno. |
Tipos de sincronização de datasets
...
Nota | ||
---|---|---|
| ||
Para que a sincronização de datasets ocorra corretamente, é necessário que a chave do banco seja configurada antes da sincronização para que não duplique os resultados. Essa configuração pode ser feita via tela no Painel de controle, selecionar a opção Plataforma ❙ Datasets > Escolher o dataset a ser sincronizado > Editar dataset > Tabela > Configurar > Campo chave para a tabela. Ou via código passando o setKey na function defineStructure. |
Existem três tipos de sincronização com datasets:
- Sincronização Comum: Este tipo de sincronização pode ser feita com qualquer dataset já implementado na plataforma. Neste modelo de sincronização toda vez que a tarefa agendada de sincronização de datasets for executada será criada uma nova tabela e todos os registros retornados pelo método createDataset serão copiados para esta nova tabela. A tabela anterior será removida do banco. Esse modelo não é recomendado para datasets que retornam muitos registros.
- Sincronização Jornalizada: Este tipo de sincronização permite a atualização e cópia incremental de registros de acordo com o retorno do método onSync do dataset. Através do método defineStructure é possível definir de forma mais detalhada quais são os campos da tabela bem como seus tipos. Também é possível criar índices e uma chave principal para obter ainda mais performance durante as consultas aos dados do dataset. No método OnSync é possível determinar quais são as linhas novas a serem adicionadas na tabela como na sincronização comum. Com os métodos updateRow e deleteRow através da configuração da chave é possível atualizar registros já existentes bem como eliminar registros. Esse modelo é o recomendado para situações em que há uma grande quantidade de dados.
Sincronização mobile: Este modelo de sincronização pode ser utilizado com qualquer dataset, seja ele sincronizado no servidor ou não, e permite a cópia local dos registros de um dataset em um dispositivo mobile que sincronize de forma offline com a plataforma. Os prazos de sincronização são configurados no aplicativo fluig Mobile.
Nota title Atenção Novos dados criados em dispositivos móveis, quando utilizando o modo offline, só estarão disponíveis para consulta em outros formulários depois que o aplicativo móvel passar por um processo de sincronização com o servidor da plataforma. Para entender mais sobre este processo, acesse nesta página o passo Configurando sincronização de datasets.
Desenvolvendo um dataset com sincronização jornalizada
...
Definindo a estrutura do dataset
Para definir a estrutura de um dataset jornalizado é necessário definir a estrutura fixa da tabela no código do dataset. Para isso no código do dataset deverá ser criado o método defineStructure.
Exclusivamente dentro desta função estão disponíveis os seguintes métodos para definição da tabela:
Retorno | Método | Descrição |
---|---|
AddColumn | AddColumn(String field, DatasetFieldType type) Cria um campo na tabela com o nome e tipo informados. O nome sempre deve ser informado em caracteres maiúsculos. O tipo de campo pode ser omitido e neste caso o campo será criado com o tipo String. Os tipos disponíveis são: DatasetFieldType.NUMBER DatasetFieldType.DATE DatasetFieldType.BOOLEAN DatasetFieldType.STRING DatasetFieldType.TEXT |
setKey | setKey(Object[] fields) Determina quais são os campos chaves para o dataset. No banco de dados será criado um índice utilizando os campos informados neste método. Esses campos serão utilizados na localização dos registros para atualização ou remoção das linhas através dos métodos updateRow e deleteRow. Importante informar apenas campos que foram previamente definidos com a função addColumn. Devem ser informados em caracteres maiúsculos. |
addIndex | addIndex(Object[] fields) Permite adicionar mais índices para obtenção de maior performance nas consultas do dataset. Devem ser informados em caracteres maiúsculos. |
Nota |
---|
Quando um campo é definido como chave (setKey) o mesmo é definido automaticamente como índice. Neste caso, o campo não poderá ser utilizado para criação de um índice único, entretanto é permitido utilizar em um índice composto. No exemplo abaixo o campo 'CE_CODIGO' foi configurado como chave, portanto não pode ser utilizado como índice único 'addIndex("CE_CODIGO")'. Não há impedimento, porém, se usar em um índice composto, como está sendo utilizado no exemplo 'addIndex([ "CE_CODIGO", "CE_LOJA", "CE_NUMTIT" ])'. |
Exemplo:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
function defineStructure() {
addColumn("CE_CODIGO", DatasetFieldType.NUMBER);
addColumn("CE_LOJA");
addColumn("CE_NUMTIT", DatasetFieldType.NUMBER);
addColumn("CE_PARCELA");
addColumn("CE_PEFIXO");
addColumn("CE_TIPO");
addColumn("CE_VALOR", DatasetFieldType.NUMBER);
addColumn("CE_INSS");
addColumn("CE_ISS");
addColumn("CE_IRRF");
addColumn("DT_TITULO", DatasetFieldType.DATE);
addColumn("CE_PIS");
addColumn("CE_COFINS");
addColumn("LOGICO", DatasetFieldType.BOOLEAN);
setKey([ "CE_CODIGO", "CE_NUMTIT" ]);
addIndex([ "CE_CODIGO" ]);
addIndex([ "CE_CODIGO", "CE_LOJA", "CE_NUMTIT" ]);
} |
Nota | ||
---|---|---|
| ||
|
Sincronização de informações
Para a transferência de dados do dataset para a tabela, deverá ser definida a função onSync que será chamada a cada execução da tarefa agendada.
Para que a sincronização aconteça deve ser criada uma tarefa no Plataforma ❙ Agendador de tarefas com o tipo 'Sincronização de dataset', selecionando qual dataset deverá ser sincronizado e em que período.
Dentro da função onSync deverá ser criado um objeto do tipo dataset onde as novas linhas deverão ser adicionadas pelo método addRow e linhas a serem atualizadas ou removidas pelos métodos updateRow e deleteRow, respectivamente.
Os métodos updateRow e deleteRow recebem uma lista de objetos que são os valores das linhas (da mesma forma que já ocorre com o método addRow).
Exemplo:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
function onSync(lastSyncDate) {
var dataset = DatasetBuilder.newDataset();
var integracao = ServiceManager.getService('FLUIG3');
var serviceLocator = integracao
.instantiate('pkgWkfSolicPagamento.FLUIGLocator');
var service = serviceLocator.getFLUIGSOAP();
var cdEmp = 1; // código empresa pagadora
var cdFilial = 0; // todas as filiais
var cdTitulo = 0; // todos os titulos
var cdPrefixo = ""
var cnpj = 0; // cnpj fornecedor
var codForn = 0; // cod universal para todos os fornecedores
var lojaForn = 0; // loja fornecedor
// Invocando o servico passando a data da ultima sincronização com a plataforma.
// O webservice foi preparado para trazer apenas os dados desde a ultima
// sincronização.
var retorno = service.CONSPAG(cdEmp, cdFilial, cdTitulo, cdPrefixo, cnpj,
codForn.toString(), lojaForn.toString(), lastSyncDate);
var arrayListaTitulo = retorno.getLISTACPAG();
for (var i = 0; i < arrayListaTitulo.length; i++) {
var r = arrayListaTitulo[i];
if (r.getCE_TIPO() == "ADD") {
dataset.addRow(new Array(r.getCE_CODIGO(), r.getCE_LOJA(), r
.getCE_NUMTIT(), r.getCE_PARCELA(), r.getCE_PEFIXO(), r
.getCE_TIPO(), r.getCE_VALOR(), r.getCE_INSS(), r
.getCE_ISS(), r.getCE_IRRF(), new java.util.Date(r.getDT_TITULO()), r
.getCE_PIS(), r.getCE_COFINS()));
} else if (r.getCE_TIPO() == "MOD") {
dataset.updateRow(new Array(r.getCE_CODIGO(), r.getCE_LOJA(), r
.getCE_NUMTIT(), r.getCE_PARCELA(), r.getCE_PEFIXO(), r
.getCE_TIPO(), r.getCE_VALOR(), r.getCE_INSS(), r
.getCE_ISS(), r.getCE_IRRF(), new java.util.Date(r.getDT_TITULO()), r
.getCE_PIS(), r.getCE_COFINS()));
} else if (r.getCE_TIPO() == "DEL") {
dataset.deleteRow(new Array(r.getCE_CODIGO(), r.getCE_LOJA(), r
.getCE_NUMTIT(), r.getCE_PARCELA(), r.getCE_PEFIXO(), r
.getCE_TIPO(), r.getCE_VALOR(), r.getCE_INSS(), r
.getCE_ISS(), r.getCE_IRRF(), new java.util.Date(r.getDT_TITULO()), r
.getCE_PIS(), r.getCE_COFINS()));
} else {
// Estado do registro é desconhecido no cache
dataset.addOrUpdateRow(new Array(r.getCE_CODIGO(), r.getCE_LOJA(), r
.getCE_NUMTIT(), r.getCE_PARCELA(), r.getCE_PEFIXO(), r
.getCE_TIPO(), r.getCE_VALOR(), r.getCE_INSS(), r
.getCE_ISS(), r.getCE_IRRF(), new java.util.Date(r.getDT_TITULO()), r
.getCE_PIS(), r.getCE_COFINS()));
}
}
return dataset;
} |
Quando for necessário salvar no banco os dados do código, o corpo do método deve ser preenchido como abaixo.
Bloco de código | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|
| ||||||||||
Bloco de código | ||||||||||
| ||||||||||
function beforeStateEntryonSync(sequenceIdlastSyncDate) { var user = getValue("WKUser"); //Cria a constraint para buscar os formulários ativos var cst1 = DatasetFactory.createConstraint("metadata#active", true, true, ConstraintType.MUST); //É obrigatório informar a constraint userSecurityId para indicar o usuário //que sera validada a permissão nos formulários var cst2 = DatasetFactory.createConstraint("userSecurityId", user, user, ConstraintType.MUST); var constraints = new Array(cst1, cst2); var datasetPrincipal = DatasetFactory.getDataset("dsExemploPaiFilho", null, constraints, null); for (var i = 0; i < datasetPrincipal.rowsCount; i++) { var documentId = datasetPrincipal.getValue(i, "metadata#id"); var documentVersion = datasetPrincipal.getValue(i, "metadata#version"); //Cria as constraints para buscar os campos filhos, passando o tablename, número da formulário e versão var c1 = DatasetFactory.createConstraint("tablename", "tabelaPecas" ,"tabelaPecas", ConstraintType.MUST); var c2 = DatasetFactory.createConstraint("metadata#id", documentId, documentId, ConstraintType.MUST); var c3 = DatasetFactory.createConstraint("metadata#version", documentVersion, documentVersion, ConstraintType.MUST); //É obrigatório informar a constraint userSecurityId para indicar o usuário //que sera validada a permissão nos formulários var c4 = DatasetFactory.createConstraint("userSecurityId", user, user, ConstraintType.MUST); var constraintsFilhos = new Array(c1, c2, c3, c4); //Busca o dataset var datasetFilhos = DatasetFactory.getDataset("dsExemploPaiFilho", null, constraintsFilhos, null); for (var j = 0; j < datasetFilhos.rowsCount; j++) { //Utiliza os campos do Dataset. Exibindo como exemplo. log.info("CAMPO 1: " + documentId); log.info("CAMPO 2: " + datasetFilhos.getValue(j, "wdk_sequence_id")); log.info("CAMPO 3: " + datasetFilhos.getValue(j, "peca")); log.info("CAMPO 4: " + datasetFilhos.getValue(j, "qtde")); } } } |
Utilizando um dos modelos acima, é possível recuperar os valores "filhos" dos formulários ativos, ou seja, a última versão criada. Existem alguns parâmetros obrigatórios que devem ser passados através de constraints, onde o valor inicial e final devem ser iguais. A forma de recuperar esses valores é opcional. Segue abaixo a nomenclatura obrigatória de cada parâmetro:
Parâmetro | Descrição | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
tablename | Atributo utilizado para nomear cada tabela filha do HTML. Exemplo:
| |||||||||||
metadata#id | Número do formulário. | |||||||||||
metadata#version | Número da versão do formulário | |||||||||||
userSecurityId | Código do usuário que será validada a permissão no formulário
|
Também é possível exibir a ordem dos campos filhos, para isso deve-se utilizar o campo wdk_sequence_id, sendo que este não poderá ser utilizado como nome de algum campo do formulário.
Resultado final do Dataset do exemplo 1:
Guia de Referência de Datasets
Dataset Factory
Retorno | Método e Descrição |
---|---|
SearchConstraint | createConstraint(java.lang.String field, java.lang.String initialValue, java.lang.String finalValue, ConstraintType type) Cria uma nova constraint para a seleção de registros do Dataset. |
java.util.List<java.lang.String> | getAvailableDatasets() Retorna uma lista de todos os Datasets disponíveis no sistema. |
DefaultDataset | getDataset(java.lang.String name, java.lang.String[] fields, SearchConstraint[] constraints, java.lang.String[] order) Carrega os dados de um Dataset. |
Dataset
Retorno | Método e Descrição |
---|---|
void | addColumn(java.lang.String colName) Adiciona uma coluna ao Dataset. |
void | addRow(java.lang.Object[] values) Adiciona uma linha ao Dataset. |
java.lang.String | getColumnName(int colNum) Retorna o nome de uma coluna do Dataset. |
java.lang.String[] | getColumnsName() Retorna um array com os nomes das colunas do Dataset. |
int | getColumnsCount() Retorna a quantidade de colunas de um Dataset. |
java.util.ArrayList<java.util.HashMap<java.lang.String,java.lang.Object>> | getMap() Retorna os valores do Dataset na forma de uma lista contendo mapas, onde cada registro do Dataset corresponde a um mapa com o nome da coluna como chave. |
int | getRowsCount() Retorna a quantidade de linhas disponíveis no Dataset. |
DefaultDataset | getSubDataset(java.lang.String field, java.lang.Object value) Retorna um subconjunto dos dados do Dataset, na forma de um novo Dataset. |
java.lang.Object | getValue(int row, int col) Retornao valor armazenado no Dataset, na linha e coluna passadas por parâmetro. |
java.lang.Object | getValue(int row, java.lang.String colName) Retorna o valor armazenado no Dataset, na linha passada e campo passados por parâmetro. |
java.lang.Object[][] | getValues() Retorna todos os valores de um Dataset, na forma de um array bidimensional. |
java.sql.ResultSet | toResultSet() Retorna um ResultSet contendo os dados do Dataset. |
...
dataset = DatasetBuilder.newDataset();
dataset.addRow(new Array(2256, "SÃO PAULO", 1058, "6", "ESPORTE"));
dataset.addRow(new Array(1874, "RECIFE", 1258, "1247690", "2", "CALÇADOS"));
dataset.addRow(new Array(1205, "RIO DE JANEIRO", 2594, "10", "MOVEIS"));
dataset.addRow(new Array(985, "FLORIANOPOLIS", 2269, "10", , "ELETRONICOS"));
return dataset;
} |
Como funciona a sincronização das informações
A forma como os dados são inseridos na base de dados é gerida pela plataforma TOTVS Fluig e desta forma o momento em que os registros são inseridos, editados ou excluídos no código do dataset, não é exatamente o mesmo momento em que, na prática, essas operações serão realizadas. Com isso, a importância em saber como funciona a sincronização e gravação de informações do dataset para tabelas de banco de dados é de utilidade geral.
Ao executar os métodos createDataset ou OnSync nas tarefas de sincronização a plataforma irá montar inicialmente em memória quatro coleções de registros que serão alimentadas de acordo com o comando utilizado pelo desenvolvedor.
Coleção | Método |
Registros novos | addRow |
Eliminados | deleteRow |
Modificados | updateRow |
Modificados ou Criados | addOrUpdateRow |
Com as coleções montadas, a ordem que a plataforma utiliza para fazer a efetivação no banco é a seguinte.
1 | Registros eliminados |
---|---|
2 | Linhas alteradas |
3 | Linhas alteradas ou criadas |
4 | Novas linhas |
Isso é necessário para que as alterações e efetivações de registros no banco sejam gerenciadas pela plataforma, afim de garantir melhor performance e obter um tempo reduzido na sincronização de informações.
Cache de dados no mobile
Quando se tem em mente um dispositivo móvel, imediatamente surge a questão do espaço ocupado por uma aplicação. A função onMobileSync é chamada apenas durante a atualização de um dataset offline já existente.
Este método serve para que os dados já sincronizados através do método onSync sejam ainda mais restritos adicionando uma nova constraint, por exemplo, ou definindo que somente algumas das colunas do dataset estejam disponíveis offline no dispositivo, evitando uso desnecessário de armazenamento.
Quando o aplicativo realiza a primeira sincronização, ao fazer o carregamento inicial dos dados, esta função não será executada.
Esta função recebe o usuário autenticado no dispositivo como parâmetro e deve retornar um objeto contendo as colunas a salvar, filtros e ordenação específicos para a Sincronização Mobile, conforme exemplo abaixo. Lembre-se de que todas as colunas informadas no código devem estar em caracteres maiúsculos.
Exemplo:
Bloco de código | ||||||||
---|---|---|---|---|---|---|---|---|
| ||||||||
function onMobileSync(user) {
var sortFields = new Array();
var constraintTitulo1 = DatasetFactory.createConstraint('CE_CODIGO',
'1', '1', ConstraintType.MUST);
var constraints = new Array(constraintTitulo1);
var colunastitulo = new Array('CE_CODIGO', 'CE_LOJA', 'CE_NUMTIT', 'CE_PARCELA',
'CE_PARCELA');
var result = {
'fields' : colunastitulo,
'constraints' : constraints,
'sortFields' : sortFields
};
return result;
} |
Acessando um Dataset com sincronização
...
O acesso a datasets sincronizados, seja ele jornalizado ou não, permanece exatamente igual ao acesso de qualquer dataset, não sendo necessário passar nenhum parâmetro extra.
Configurando a sincronização de datasets
...
A partir da atualização 1.6.2 o Painel de controle disponibiliza a opção Datasets, com uma listagem de todos os datasets cadastrados na plataforma. Nessa tela é possível:
- Ligar ou desligar a sincronização de datasets em tabelas do servidor.
- Ligar ou desligar cache de informações de datasets em dispositivos mobile.
- Editar agendamentos para os datasets sincronizados.
- Consultar o dataset - consulta do código fonte do dataset.
- Consultar os dados do dataset
- Apagar todos os dados - Permite apagar os dados sincronizados para reiniciar a sincronização.
Figura 3 - Tela de dataset na atualização 1.6.5
Configurando comportamento de acesso a datasets em dispositivos mobile
É possível definir como será o comportamento do dispositivo mobile para realização do cache de informações, bem como o acesso a essas informações de acordo com o estado do dispositivo. Para isso, acione o link da coluna Offline mobile.
Figura 4 - Tela de Comportamento Mobile do dataset
Nesta tela temos as seguintes opções:
- Utilizar cache em dispositivos móveis: Define se o dataset terá ou não cache em dispositivos móveis.
- Tempo de expiração do cache mobile: Determina o período em que o cache será considerado válido desde a ultima sincronização de dispositivo.
- Não utilizar cache quando o dispositivo móvel estive online: Determina se o dispositivo consultará os dados do cache do dataset mesmo que o dispositivo esteja online através de redes wifi ou 3g/4g.
Utilize os botão salvar para confirmar as alterações.
Configurando sincronização de dados para o servidor da plataforma
Para definir que determinado dataset irá sincronizar as linhas obtidas para dentro de uma tabela da plataforma, é preciso clicar no link da coluna Sincronização, que abre a tela abaixo.
Figura 5 - Tela de Sincronização do dataset com o servidor
A opção Sincronizar com o servidor? irá ativar o modo de sincronia de dados no servidor.
Nota |
---|
Ao desligar a sincronização de um dataset que estava sendo sincronizado e jornalizado, lembre-se que as tabelas que abrigam os dados e as tarefas de sincronização serão removidas e que, por consequência, todos os dados sincronizados até aquele momento serão perdidos. Com a sincronização desligada, os dados que serão listados para este dataset são os dados obtidos pelo método createDataset. |
Apagar dados
Essa opção permite ao administrador remover a tabela que contém os dados sincronizados com o servidor. É importante notar que os dados não serão apagados imediatamente após a confirmação da mensagem, e sim, na próxima execução da tarefa de sincronização. A próxima tarefa de sincronização criará uma nova tabela gravando os dados daquela execução. A tabela que abrigava os dados antes da ordem de eliminação de dados será removida junto com seus registros.
Para apagar os dados, é preciso acionar o link da coluna Sincronização, que abre a tela de Sincronização (Figura 5), e então acionar a opção Apagar dados.
Editar agendamentos
Após definir que determinado dataset é sincronizado no servidor da plataforma, é preciso agendar pelo menos uma execução da tarefa de sincronia do dataset. Para acessar essa opção, é preciso acionar o link da coluna Sincronização, que abre a tela de Sincronização (Figura 5), e acionar a opção Editar agendamento.
Figura 6 - Tela de configuração do agendamento da sincronização
Nesta tela deverão ser preenchidos obrigatoriamente os seguintes campos:
- Descrição: Descrição obrigatória que irá identificar a tarefa na lista de tarefa agendadas.
- Tipo: Tipo da tarefa (o valor sincronização de datasets virá selecionado por padrão).
- Dataset: O dataset que será sincronizado (o dataset selecionado na tela anterior virá selecionado por padrão) .
As outras informações se referem a frequência e horário de execução da tarefa e segue o mesmo padrão dos outros tipos de tarefa agendada existentes. Para mais informações, consulte a documentação de usuário do Plataforma ❙ Agendador de tarefas.
Consultando dataset
Essa opção possibilita a consulta dos resultados do dataset no banco de dados da plataforma. Qualquer tipo de dataset pode ser consultado, mesmo aqueles que não tenham sincronização.
Para realizar a consulta, acione o ícone presente na coluna Mais ações e, em seguida, a opção Consultar.
Figura 7 - Consulta aos dados do dataset