Package systextil.dao
Faz o mapeamento de tabelas de banco de dados do Systêxtil 5 para classes Java, utilizando orientação a objetos e funcionalidades de baixo nível. Este mapeamento tem por objetivo possibilitar a substituição do uso de comandos SQL distribuídos ao longo de extensos códigos-fonte convertidos do Vision por objetos Java com tipagem forte e comunicação automática com o banco de dados.
Não existe nesta package, ainda, uma organização hierárquica ou em módulos entre as classes. Todas são consideradas no mesmo nível. Não há modularização de negócio, e sim de arquitetura.
As classes nesta package não devem fazer referências a classes em outras packages
mais específicas.
Esta package forma uma camada de arquitetura de negócio acima das camadas de
persistência (JDBC e systextil-connection
) e abaixo das demais
camadas de negócio (systextil-bo
e systextil-function
).
Estas classes podem fazer referências a classes do projeto systextil-connection
e da package systextil
. Não podem de maneira nenhuma fazer referências
a funções e a processos, para não prejudicar a modularização, mas podem ser
referenciadas por eles. Não podem fazer referência a outras classes utilitárias,
como classes de tratamento de mensagens, de acesso a arquivos, de geração de relatórios, etc. nem
podem ser referenciadas por elas, porque se destinam exclusivamente
a processos de negócio.
As classes desta package em geral fornecem objetos de acesso a dados (DAO) e não
podem conter lógicas complexas, como cálculos, validações e processos. Esse tipo de coisa
deve ficar com classes de processos e funções. Por isso, também, estas classes
nunca lançam TagException
. (Ainda está em estudos se é permitido
lançar RuleViolation
.)
Cada classe que representa uma tabela do Systêxtil 5 possui os comandos SQL associados a essa tabela. Somente essa classe pode conter comandos SQL associados a essa tabela, e não pode conter comandos SQL associados a outra tabela. Com isso cada classe encapsula os comandos SQL que se referem à sua tabela. O código-fonte de processos que utilizam essa tabela passa a utilizar objetos dessa classe no lugar de executar diretamente comandos SQL. Gradativamente, vai-se eliminando a execução de comandos SQL em processos de negócio e em funções. Os processos passam a utilizar cada vez mais orientação a objetos de verdade.
É permitido - e mesmo recomendado - que objetos de uma classe façam referência a objetos de outra classe desta mesma package com os quais possuam uma relação forte - p. ex. a capa de um pedido obter os dados do cliente associado, bem como carregar os seus próprios itens, e os itens de um pedido possuírem uma referência à sua capa e carregarem os dados dos produtos. Não há limites para as classes desta package fazerem referências umas às outras, sempre respeitando que uma jamais execute um comando SQL na tabela da outra, e que essas chamadas não envolvam regras e cálculos complexos. No entanto, é bem-vinda uma certa preocupação com a futura modularização do sistema em módulos especialistas em negócios.
- Por exemplo: onde deve estar o método que traga uma lista de pedidos de um cliente?
- a) um método da classe de clientes
- b) um método estático da classe de pedidos
- Como os pedidos dependem do cliente e o cliente não depende dos pedidos, então a resposta correta é b).
São permitidos cálculos bem elementares na obtenção de dados de um objeto, p. ex. obter o total dos itens de um pedido. Cálculos mais complexos, como a obtenção de descontos, aplicação de tabelas de preços, impostos, parcelamentos, são proibidos nesta package.
É importante ter sempre em mente as finalidades das classes desta package:
- gerar objetos contendo os dados que foram lidos de um registro, em modo somente-leitura;
- prover métodos para manipulação da tabela mediante comandos SQL elementares
(
insert
,update
edelete
); - obter facilmente outros objetos relacionados diretamente ao objeto atual.
Os dados de um registro são alterados exclusivamente mediante métodos que executam
update
. Não existem setters. Não existem métodos para persistir
alterações no objeto.
Como os dados dos objetos são somente para leitura, eles são válidos somente enquanto
o registro original não é alterado no banco de dados. Assim que esse registro é
alterado - mediante update
ou alguma trigger - o objeto
atual deve ser descartado e um novo deve ser obtido a partir de nova leitura do
registro. Essa forma de trabalho é perfeitamente compatível com a programação
atual do Systêxtil 5, que lê variáveis a partir de registros e repete as leituras
conforme a necessidade. Assim, a conversão de Vision para Java neste framework
fica bastante direta.
Detalhamento das regras para construção das classes
O nome da classe segue o padrão Java de nomenclatura de classes, e reflete a função da tabela nos processos de negócio do Systêxtil - no singular.
- Se uma tabela não tiver propósito em existir independentemente de uma estrutura
de tabelas já existente, pode ser conveniente atribuir à sua classe um nome que reflita
essa estrutura, para maior clareza quando estiverem ordenadas alfabeticamente. Por exemplo,
a classe que corresponde a endereços dos clientes fica melhor representada se for chamada
de
ClienteEndereco
; a de item de pedido de venda seriaPedidoVendaItem
.
As colunas da tabela ficam representadas por campos somente-leitura. Isso significa
que todos os campos correspondentes a colunas são definidos como public final
e são preenchidos no construtor, a partir da leitura de um registro da tabela.
- Os nomes desses campos devem corresponder exatamente aos nomes das colunas correspondentes na tabela do banco de dados, em minúsculas. Algumas exceções são apresentadas mais adiante.
- O tipo dos campos é baseado no tipo das colunas, com as mesmas regras aplicadas
pelo Vision - inclusive considerando que colunas definidas com dois dígitos
decimais são mapeadas para campos
Amount
. - O preenchimento e leitura dos campos não é feito usando setters e getters, do padrão de JavaBeans, pois isso polui demais o código-fonte das classes e a API, e não tem necessidade, pois o valor desses campos nunca muda.
- O uso de frameworks padronizados para persistência, como JPA, Hibernate, é inadequado neste contexto, pois estamos trabalhando com um legado de tabelas que não estão otimamente normalizadas e que são manipuladas mediante comandos SQL em profusão. A evolução a partir desse legado deve continuar mantendo o controle sobre os comandos SQL que fazem a manutenção dos dados no banco, sem que para isso os mesmos comandos SQL sejam copiados ou escritos várias e várias vezes nas classes de processos de negócio. Delegar a execução de comandos SQL a frameworks que os constroem automaticamente não é viável neste momento.
O construtor tem como único objetivo inicializar os campos do objeto. Por isso, esse
construtor é private
e é invocado exclusivamente em outro método
private static make(AppConnection cn)
que retorna o objeto inicializado
com os valores extraídos de um registro do banco de dados. É esse método que será
invocado pelos demais métodos públicos e estáticos da classe, retornando um objeto
ou uma coleção de objetos lidos do banco de dados.
Métodos do tipo update
ou delete
que afetam o registro correspondente
ao próprio objeto devem retornar void
. Métodos que afetam registros mediante
um filtro devem ser static
e retornar a quantidade de registros afetados.
Métodos do tipo insert
são static
e normalmente retornam void
.
Em algum momento pode ser conveniente fazer que um método assim sempre retorne o objeto
que foi inserido, para que ele já possa ser utilizado em seguida, quando isso for útil.
Métodos que executam update
devem ter seu nome iniciando com update
e
complementado com o nome dos campos que são atualizados, ou uma descrição da finalidade desse
update
. Exemplos: public void updateSituacao(AppConnection conn, int cod_situacao)
e
public static int updateZerarNFe(AppConnection conn, int cod_solicitacao_nfe)
.
Todos os métodos que devem fazer alguma operação no banco de dados, inclusive os métodos que
buscam outros objetos associados ao objeto atual, devem receber uma AppConnection
como primeiro argumento.
A única maneira de obter uma instância a partir de sua chave primária é através do método estático
get
. Esse método pode ser sobrecarregado para aceitar como argumentos
agrupadores de códigos (p. ex. Cnpj
) ou objetos dos quais a própria instância
dependa (p. ex. a capa do item) para permitir que se evite o tráfego de códigos elementares
quando já se possui objetos prontos com as informações necessárias.
Métodos que retornam uma coleção de objetos a partir de uma busca devem ter seu nome
começando com list
e complementado com o que for necessário para a compreensão
de sua finalidade. Uma exceção é quando traz a lista de todos os objetos associados ao objeto atual,
quando continua seguindo o padrão getAlgo
. Alguns exemplos:
- A lista de itens de uma capa:
public static Item[] list(AppConnection conn, Capa capa)
na classeItem
. - A lista de itens desta capa:
public Item[] getItens(AppConnection conn)
na classeCapa
. (Curiosamente, este método deve invocar o anterior.) - A lista de itens bloqueados por ordem de data:
public static Item[] listBloqueadosOrderByDate(AppConnection conn, Capa capa)
na classeItem
.
Instâncias "nulas"
No Systêxtil 5 em Vision, é comum que algumas variáveis sejam preenchidas na consulta
a um registro de uma tabela, e se esse registro não existir (isto é, status <> 0
),
essas variáveis recebem um valor padrão, como zero ou vazio.
Neste framework, se não existir um registro a retornar através do método estático
get
, o retorno é nulo. Em programas convertidos do Vision para Java, se o método
get
retornar nulo, é preciso preencher aquelas variáveis com valores padrão,
o que pode ser muito inconveniente. O código fica poluído com testes do tipo
if(obj != null) {/* valores lidos */} else {/* valores padrão */}
.
Por conveniência, algumas classes possuem definida uma instância fictícia previamente preenchida
com valores padrão, chamada NULL_INSTANCE
. Essa instância pode ser usada como
retorno nos casos em que não é encontrado registro no banco - desde que o método que a retorna
tenha NotNull
no nome. Por exemplo, um método chamado getNaturezaDeOperacao
retorna nulo se o registro não existir, e o método getNaturezaDeOperacaoNotNull
retorna NaturezaDeOperacao.NULL_INSTANCE
nessa situação. O uso de métodos
NotNull
garante que o retorno nunca será nulo, e não é preciso testar essa condição.
Herança
Apesar das classes desta package serem destinadas primariamente a facilitar o acesso a dados de uma e somente uma tabela do banco de dados, sem o uso de regras de negócios e de processos, a aplicação de técnicas de orientação a objetos a estas classes facilita tremendamente seu uso em processos complexos.
A presença de redundâncias de colunas em tabelas que possuem finalidades parecidas pode ser contornada facilmente utilizando classes abstratas e herança.
Por exemplo: as classes correspondentes a notas fiscais de entrada e notas fiscais de saída, apesar de representarem tabelas diferentes, ambas são subclasses de uma classe abstrata de notas fiscais, a qual centraliza características e métodos que são comuns a ambas. Desta maneira, processos que se aplicam igualmente a notas fiscais de entrada e de saída não precisam ter sua lógica duplicada.
Outro exemplo: as classes de clientes e de fornecedores são subclasses de uma classe abstrata que centraliza características e métodos que são comuns a empresas em geral.
Quando se utiliza herança, pode ser necessário utilizar nomes de campos que não sejam idênticos aos das colunas no banco de dados para unificar campos comuns a algumas classes. Somente nestas situações é permitido utilizar nomes de campos ligeiramente diferentes dos nomes das colunas originais. Isto também se aplica a subclasses de agrupadores de códigos.
Agrupadores de códigos
Nesta package encontram-se também classes que servem para agrupar códigos compostos que são
muito usados ao longo do sistema. Exemplos são as que agrupam os códigos de CNPJ, os
códigos de produto e de alternativa. Estas classes não estão vinculadas a tabelas do banco
de dados. Sempre que possível, o uso de objetos dessas classes substitui a leitura ou
o fornecimento de grupos de códigos ou campos que são sempre usados juntos, o que é muito melhor que
ficar manipulando objetos tão genéricos como códigos numéricos e String
s.
Algumas classes de DAO inclusive são subclasses desses agrupadores, pois seus objetos
podem ser utilizados diretamente com a mesma finalidade.
-
ClassDescriptionRepresenta a tabela
PEDI_170
Representa a tabelaPEDI_160
Representa a tabelaPEDI_165
Representa a tabelaBASI_070
Representa a tabelaBASI_295
Representa a tabelaBASI_541
Representa a tabelaBASI_500
Representa a tabelaBASI_510
Representa a tabelaBASI_260
Representa a tabelaFATU_190
Representa a tabelaBASI_185
Representa a tabelaBASI_161
Representa a tabelaCREC_170
.Representa a tabelaCREC_180
.Representa a tabelaCPAG_030
.Representa a tabelaBASI_160
Representa a tabelaBASI_240
Representa a tabelaPEDI_010
Representa a tabelaPEDI_150
Representa a tabelaINTE_150
Representa a tabelaINTE_010
Encapsula campos e regras que são comuns a clientes e fornecedores.Representa a tabelaCONT_540
Representa a identificação de uma máquina;Representa a tabelaBASI_140
Representa a tabelaPEDI_070
Representa a tabelaSUPR_050
Representa a tabelaPEDI_076
Representa a tabelaPEDI_075
Representa a tabelaPEDI_005
Representa uma conta bancária genérica, largamente utilizada em várias tabelas do sistema.Representa a tabelaCPAG_026
.Representa a tabelaCPAG_027
.Representa a tabelaBASI_150
Representa a tabelaBASI_100
Representa a tabelaBASI_187
Representa a tabelaOPER_126
Representa a tabelaBASI_205
Representa a tabelaCREC_102
Representa a tabelaFATU_036
Representa a tabelaFATU_070
Representa a tabelaFINA_030
Representa a tabelaFATU_500
Representa a tabelaEXEC_020
Representa a tabelaOBRF_180
Representa a tabelaFATU_507
Representa a tabelaESTQ_110
Representa a tabelaBASI_167
Representa a tabelaMQOP_005
Representa a tabelaESTQ_300
.Representa a tabelaCONT_500
.Representa a tabelaSUPR_010
Representa a tabelaMQOP_115
Representa a tabelaCONT_010
.Representa a tabelaCONT_600
Representa a tabelaCONT_050
Representa a tabelaCONT_520
Representa a tabelaMAPA_ECF
Utilitário para armazenar os campos que são usados como chave na importação dos dados de lojas.Representa a tabelaMQOP_030
Representa a tabelaMQOP_035
Representa a tabelaMQOP_010
Representa a tabelaMQOP_020
Representa a tabelaOBRF_874
Representa uma mensagem que pode ser originada de diferentes tabelas do sistema.Representa a tabelaEXEC_130
Representa a tabelaBASI_270
Representa a tabelaPEDI_080
Representa a tabelaOBRF_158
Centraliza a obtenção dos níveis de quebra da empresa ou do cliente, conforme for o caso.Representa a tabelaOBRF_122
(Carta de Correção Eletrônica)Representa a tabelaOBRF_010
Representa a tabelaOBRF_015
Representa a tabelaFATU_050
Representa a tabelaFATU_060
Representa a tabelaOBRF_875
Representa a tabelaOBRF_002
Representa a tabelaI_FATU_050
Todos os atributos estão publicos pois essa classeDAO
só é utilizada no programainte_f148
e esse programa segue uma regra onde é necessário alterar alguns campos dessa classe com base em um cadastro De:Para antes de gravar o mesmo na tabela oficial.Representa a tabelaI_FATU_060
Todos os atributos estão publicos pois essa classeDAO
só é utilizada no programainte_f148
e esse programa segue uma regra onde é necessário alterar alguns campos dessa classe com base em um cadastro De:Para antes de gravar o mesmo na tabela oficial.Classe abstrata para itens de nota fiscal de entrada e de saída.Representa a tabelaFATU_052
Representa a tabelaFATU_010
.Representa a tabelaFATU_505
Representa a tabelaMQOP_040
Representa a tabelaLOJA_200
.Representa a tabelaLOJA_210
.Representa a tabelaLOJA_075
Representa a tabelaPCPC_072
Representa a tabelaPCPB_030
Representa a tabelaPCPC_045
.Representa a tabelaPCPC_040
.Representa a tabelaPCPB_020
Representa a tabelaPCPC_020
Representa a tabelaPCPT_025
Representa a tabelaOBRF_080
Representa a tabelaOBRF_087
Representa a tabelaOBRF_086
Representa a tabelaOBRF_082
Representa a tabelaOBRF_081
Representa a tabelaPCPB_040
Representa a tabelaFATU_075
Representa a tabelaLOJA_076
.Pode ser estendida para usar diferentes fontes de pagamentos para os processos que envolvem pagamentos, como associação de cheques, por exemplo.Representa a tabelaBASI_165
Representa a tabelaOBRF_205
Representa a tabelaCONT_560
Representa as tabelas de parametrosFATU_500
,FATU_501
,FATU_502
,FATU_503
eFATU_504
Representa a tabelaEMPR_002
eEMPR_001
É a superclasse para classes que utilizam parcelamento.Representa a tabelaPEDI_113
Representa a tabelaSUPR_605
Representa a tabelaPEDI_100
Representa a tabelaBASI_161
Representa a tabelaINTE_100
Representa a tabelaPEDI_110
Representa a tabelaINTE_110
Representa a tabelaPEDI_101
Representa a tabelaFATU_071
Representa a tabelaCONT_510
representa a dabelaPCPC_010
Representa a tabelaCONT_530
Representa a tabelaCONT_535
Representa a tabelaPEDI_050
Representa a tabelaCPAG_020
.Representa a tabelaBASI_010
Representa a tabelaBASI_230
Representa a tabelaBASI_290
Representa a tabelaBASI_050
.Representa a tabelaBASI_040
.Encapsula dados da montagem de componentes para serem usados em processos de cálculos, que são o código do componente e o consumo.Emula as funcionalidades do par composicao - perc_composicao que é usado emReferencia
,Tamanho
e cálculos que os manipulam.Representa a tabelaBASI_015
.Representa a tabelaBASI_350
.Representa a tabelaRCNB_075
Representa a tabelaBASI_095
.Representa a tabelaBASI_750
Representa a tabelaBASI_400
Representa a tabelaBASI_120
.Representa a tabelaESTQ_040
Representa a tabelaBASI_060
.Representa a tabelaOPER_550
Representa a tabelaBASI_030
Representa a tabelaBASI_544
Representa a tabelaPEDI_040
Representa a tabelaOBRF_260
Representa a tabelaCONT_550
Representa a tabelaPEDI_020
Representa a tabelaPEDI_021
Representa a tabelaMQOP_050
Representa a tabelaBASI_105
Representa a tabelaFATU_030
Representa a tabelaBASI_020
Representa a tabelaBASI_023
Representa a tabelaBASI_220
Representa a tabelaBASI_340
Representa a tabelaBASI_110
.Representa a tabelaCPAG_010
.Representa a tabelaRCNB_302
Representa a tabelaCPAG_040
Representa a tabelaESTQ_005
Representa a tabelaHDOC_030
Representa a viewVI_CONS_NFE
Representa a tabelaPCPC_320