BISDAO: mudanças entre as edições
Sem resumo de edição |
Sem resumo de edição |
||
(10 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 1: | Linha 1: | ||
A persistência do BIS é automatizada como um sistema de ORM | A persistência do BIS é automatizada como um sistema de ORM próprio chamado de BISDAO. Embora não seja tão maleável quanto os sistemas já consolidados no mercado, tem ótima performance, é melhor adaptado ao Framework do BIS e por não fazer injeção de código permite que VOs e métodos de persistência customizados sejam alterados por hot-deploy. | ||
O principal objetivo do BISDAO é receber os VOs e persisti-lo (inserindo/atualizando), exclui-lo ou encontra-los no banco de dados automaticamente. Abstraindo a questão objeto x relacional do banco de dados, e diminuindo (ou eliminando na grande maioria dos casos) a necessidade de implementação códigos SQL pelo desenvolvedor. | |||
= Regras do Funcionamento = | |||
# Embora utilize os conceitos do banco de dados, não segue os padrões definidos no JPA. Assim, nenhuma annotation do JPA é utilizada nos VOs do BIS. | |||
# O BISDAO manipula os VOs automaticamente. E não aceita nenhum outro tipo de objeto, isto é, para ser persistido '''é obrigatório que a entidade seja descendente do [[BISVO]]'''. | |||
= Estrutura do Banco de Dados = | |||
O BIS é uma plataforma que suporta múltiplas empresas sendo manipuladas pela mesmas instância. Assim um mesmo servidor e mesmo banco de dados será utilizado para gerenciar várias empresas. Para isso o sistema utilizará vários "schemas" (ou catálogos) do banco de dados, sendo: | O BIS é uma plataforma que suporta múltiplas empresas sendo manipuladas pela mesmas instância. Assim um mesmo servidor e mesmo banco de dados será utilizado para gerenciar várias empresas. Para isso o sistema utilizará vários "schemas" (ou catálogos) do banco de dados, sendo: | ||
Linha 15: | Linha 18: | ||
* '''bis_<empresa>''' - com este nome deve existir um schema para cada empresa que o sistema gerencia. Isto é, para cada empresa que o BIS atender, um novo schema é criado para armazenar os dados específicos da empresa, como itens/produtos sendo vendidos, documentos fiscais, etc. | * '''bis_<empresa>''' - com este nome deve existir um schema para cada empresa que o sistema gerencia. Isto é, para cada empresa que o BIS atender, um novo schema é criado para armazenar os dados específicos da empresa, como itens/produtos sendo vendidos, documentos fiscais, etc. | ||
== Configuração das FK == | |||
Ao criar a associação entre as tabelas do banco de dados devemos seguir as seguintes regras para o bom funcionamento do BISDAO: | Ao criar a associação entre as tabelas do banco de dados devemos seguir as seguintes regras para o bom funcionamento do BISDAO: | ||
Linha 37: | Linha 41: | ||
{{nota|Objeto Em Uso e Não pode ser Excluído|Quando o BIS recebe o erro de que "falha de constraint" do banco de dados, ele assume que não pode ser excluído porque o objeto está em uso por algum outro objeto e retorna uma exception específica para este tipo de erro. | |||
É ma exception do tipo Critica com o código de erro "ERR100067". Essa exception deve ser tratada quando se espera que esse tipo de coisa possa acontecer, como por exemplo, um objeto que pode ser excluído desde que ainda não esteja em uso. Apesar de ter uma mensagem padrão no Bundle para este código, é recomendável criar uma mensagem para cada caso específico.}} | |||
= Relacionamento Entre Objetos = | |||
Os relacionamentos entre objetos serão declarados de acordo com o "tipo do relacionamento" constituído entre eles para que o BISDAO saiba como proceder quando for atualizar, inserir ou excluir os objetos. Entender o relacionamento entre os dois define a boa arquitetura ao criar os objetos: | Os relacionamentos entre objetos serão declarados de acordo com o "tipo do relacionamento" constituído entre eles para que o BISDAO saiba como proceder quando for atualizar, inserir ou excluir os objetos. Entender o relacionamento entre os dois define a boa arquitetura ao criar os objetos: | ||
== Associação == | |||
O tipo de relacionamento '''Associação''' é utilizando quando ambos os objetos existem separadamente, mesmo que não tenham vínculos. Por exemplo: | O tipo de relacionamento '''Associação''' é utilizando quando ambos os objetos existem separadamente, mesmo que não tenham vínculos. Por exemplo: | ||
Linha 52: | Linha 60: | ||
* '''Alteração''' - Em caso de alteração o objeto será comparado com o atual no banco de dados. Objetos que não estejam mais presentes no objeto sendo persistido, terão sua associação removida, novos objetos terão associação criada. A contra-parte nunca será excluída, e nem criada. | * '''Alteração''' - Em caso de alteração o objeto será comparado com o atual no banco de dados. Objetos que não estejam mais presentes no objeto sendo persistido, terão sua associação removida, novos objetos terão associação criada. A contra-parte nunca será excluída, e nem criada. | ||
== Composição == | |||
O relacionamento do tipo composição indica que o objeto associação é uma "extensão" deste objeto. Ou seja, ele faz parte do objeto principal, e como tal será manipulando junto com o objeto pai. Por exemplo: | O relacionamento do tipo composição indica que o objeto associação é uma "extensão" deste objeto. Ou seja, ele faz parte do objeto principal, e como tal será manipulando junto com o objeto pai. Por exemplo: | ||
Linha 64: | Linha 72: | ||
== Annotation @BISDAO == | |||
Toda entidade deve ter a Class Annotation ''@BISDAO'' para configurar a tabela a qual o objeto se refere. | Toda entidade deve ter a Class Annotation ''@BISDAO'' para configurar a tabela a qual o objeto se refere. | ||
Linha 79: | Linha 87: | ||
* '''table''' - Indica o nome da tabela onde o conteúdo deste objeto é guardado. | * '''table''' - Indica o nome da tabela onde o conteúdo deste objeto é guardado. | ||
== Relacionamento Atributo do Objeto x Coluna do BD == | |||
Para que um atributo do objeto seja relacionado corretamente com uma coluna da tabela (especificada na Annotation @BISDAO) é necessário que o atributo tenha uma @[[BISMeta Annotations]]. Nela constarão várias informações sobre o atributo, incluindo a coluna. '''Caso o nome da coluna não seja especificado, o BISDAO assume que o nome da coluna é exatamente o mesmo nome do atributo''', ou seja, caso o mesmo nome seja utilizado na coluna do banco quando no atributo do objeto, não é necessário especificar o atributo coluna na Annotation. Isso deixa o código menos poluído. | Para que um atributo do objeto seja relacionado corretamente com uma coluna da tabela (especificada na Annotation @BISDAO) é necessário que o atributo tenha uma @[[BISMeta Annotations]]. Nela constarão várias informações sobre o atributo, incluindo a coluna. '''Caso o nome da coluna não seja especificado, o BISDAO assume que o nome da coluna é exatamente o mesmo nome do atributo''', ou seja, caso o mesmo nome seja utilizado na coluna do banco quando no atributo do objeto, não é necessário especificar o atributo coluna na Annotation. Isso deixa o código menos poluído. | ||
= Mapeamento do Relacionamento = | |||
O mapeamento de todos os relacionamentos são feitos através da @BISMetaRelationshipField. | |||
== Associação 1:1 == | |||
== Associação 1:N == | |||
[[File:Associacao1N.png|center|frame|Associação OneToMany entre BISCompanyVO e BISFileVO]] | |||
A associação 1:N do exemplo é unilateral, já que só o FileVO tem conhecimento do vínculo. A descrição do mapeamento feito no FileVO é a mesma utilizada em uma associação 1:1. | |||
{{java|FileVO|<syntaxhighlight lang="java"> | |||
@BISMetaRelationshipField(column = "k_company_id", relationship = RelationshipTypes.ASSOCIATION, ...) | |||
private BISCompanyVO companyVO = null; | |||
</syntaxhighlight>}} | |||
Sendo os atributos: | |||
* '''relationship''' - Definido como ASSOCIATION para indicar a associação (tanto para 1:N quanto 1:1). | |||
* '''column''' - nome da coluna que tem o ID da entidade associada. '''Utilizado somente se a coluna com o ID estiver na tabela desta entidade'''. | |||
* '''columnMapped''' - nome da coluna que tem o ID do objeto da contra-parte. '''Utilizado somente se a coluna com o ID desta entidade (FK) estiver na tabela da entidade associada'''. | |||
* '''targetRelationship''' - Classe do objeto utilizado na contra-parte. Normalmente a mesma classe passada no "generics" da coleção. '''Quando não é uma coleção de objeto, este atributo pode ser omitido e será usado o próprio tipo do Field declarado na classe'''. Neste caso o BISCompanyVO. | |||
== Associação N:N == | |||
[[File:AssociacaoNN.png|center|frame|Associação ManyToMany entre BISCompanyVO e BISUserVO]] | |||
A associação N:N (Many To Many) exige uma tabela intermediária para gravar as associações. Nos objetos o relacionamento é feito da seguinte maneira: | |||
{{java|BISCompanyVO|<syntaxhighlight lang="java"> | |||
@BISMetaRelationshipField(relationship = RelationshipTypes.MANY_TO_MANY, joinTable = "k_user_company", column = "k_company_id", columnMapped = "k_user_id", targetRelationship = BISUserVO.class, ...) | |||
private List<BISUserVO> users = null; | |||
</syntaxhighlight>}} | |||
{{java|BISUserVO|<syntaxhighlight lang="java"> | |||
@BISMetaRelationshipField(relationship = RelationshipTypes.MANY_TO_MANY, joinTable = "k_user_company", column = "k_user_id", columnMapped = "k_company_id", targetRelationship = BISCompanyVO.class, ...) | |||
private List<BISCompanyVO> companies = null; | |||
</syntaxhighlight>}} | |||
Sendo os atributos: | |||
* '''relationship''' - Em ambas as entidades definido como MANY_TO_MANY para indicar a associação de N:N. | |||
* '''joinTable''' - Nome da tabela de join entre as tabelas dos objetos. | |||
* '''column''' - nome da coluna que tem o ID da entidade onde está a declaração. | |||
* '''columnMapped''' - nome da coluna que tem o ID do objeto da contra-parte. | |||
* '''targetRelationship''' - Classe do objeto utilizado na contra-parte. Normalmente a mesma classe passada no "generics" da coleção. | |||
{{nota|Schema da Tabela de Join|A tabela de join é procurada dentro do mesmo schema da entidade pai. Ou seja a entidade que declara o BISMetaRelationshipField. | |||
Quando há relacionamento entre tabelas do schema da empresa e do schema do kernel, a entidade do kernel não conhece o relacionamento, logo ela não declara o relacionamento. | |||
Além disso, o relacionamento entre tabelas da empresa só pode estar dentro do schema da empresa, caso contrário a tabela de join teria de ter uma coluna para cada tabela de schema diferente. Completamente impossível.}} | |||
== Composição 1:1 == | |||
[[File:Composicao11.png|center|frame|Composição OneToOne entre FileVO e FileContentVO]] | |||
A composição 1:1 tem basicamente a função de separar uma coleção de dados do objeto principal, podendo deixar o objeto com os dados principais mais leve. Ou separar uma coleção de dados não obrigatórios. No exemplo abaixo, separamos o conteúdo do arquivo (FileContentVO) dos dados do arquivo (FileVO). Assim quando precisamos recuperar as informações sobre os arquivos do banco não temos de obter todo o conteúdo do arquivo deixando uma conexão pesada e muitos dados na memória. | |||
{{java|FileVO|<syntaxhighlight lang="java"> | |||
@BISMetaRelationshipField(columnMapped = "k_file_id", relationship = RelationshipTypes.COMPOSITION, ...) | |||
private FileContentVO fileContentVO = null; | |||
</syntaxhighlight>}} | |||
Sendo os atributos: | |||
* '''relationship''' - Definido como COMPOSITION para indicar a composição (tanto para 1:N quanto 1:1). | |||
* '''column''' - nome da coluna que tem o ID da entidade associada. '''Utilizado somente se a coluna com o ID estiver na tabela desta entidade'''. | |||
* '''columnMapped''' - nome da coluna que tem o nosso ID na tabela da contra-parte. '''Utilizado somente se a coluna com o ID desta entidade (FK) estiver na tabela da entidade associada'''. | |||
* '''targetRelationship''' - Classe do objeto utilizado na contra-parte. Normalmente a mesma classe passada no "generics" da coleção. '''Quando não é uma coleção de objeto, este atributo pode ser omitido e será usado o próprio tipo do Field declarado na classe'''. Neste caso o FileContentVO. | |||
=== | {{java|FileContentVO|<syntaxhighlight lang="java"> | ||
@BISMetaRelationshipField(relationship = RelationshipTypes.PARENT_ASSOCIATION, column = "k_file_id") | |||
private FileVO fileVO = null; | |||
</syntaxhighlight>}} | |||
Sendo os atributos: | |||
* '''relationship''' - Definido como PARENT_ASSOCIATION para indicar que esta entidade é a filha de uma composição (objeto submisso) e que este field se relaciona com o objeto pai. | |||
* '''column''' - nome da coluna que tem o ID da entidade associada. '''Utilizado somente se a coluna com o ID estiver na tabela desta entidade'''. | |||
* '''columnMapped''' - nome da coluna que tem o nosso ID na tabela da contra-parte. '''Utilizado somente se a coluna com o ID desta entidade (FK) estiver na tabela da entidade associada'''. | |||
* '''targetRelationship''' - Classe do objeto utilizado na contra-parte. Normalmente a mesma classe passada no "generics" da coleção. '''Quando não é uma coleção de objeto, este atributo pode ser omitido e será usado o próprio tipo do Field declarado na classe'''. Neste caso o FileVO. | |||
== Composição 1:N == | |||
== Composição N:N == | |||
O BIS não permite esse tipo de composição. Isso porque esse relacionamento indica o reaproveitamento dos objetos filhos por outros pais. Neste caso o objeto filho deve ter sua "autonomia" e viver independente do pai. Casos como esses devem ser transformados em Associação N:N. | O BIS não permite esse tipo de composição. Isso porque esse relacionamento indica o reaproveitamento dos objetos filhos por outros pais. Neste caso o objeto filho deve ter sua "autonomia" e viver independente do pai. Casos como esses devem ser transformados em Associação N:N. | ||
= Implementação = | |||
O BISDAO quando tem seus métodos chamados, ele analisa a classe da entidade e a primeira coisa que ele faz é criar um objeto de mapeamento - o '''DAOMap'''. | |||
O DAOMap gerado cria uma estrutura de mapeamento entre a entidade e a tabela, e em seguida entre os atributos da entidade e as colunas das tabelas. Ele também analisa os atributos marcamos dom a '''BISMetaRelationshipField''' e cria a estrutura de mapeamento entre as tabelas e as '''FKs''', o que normalmente depois é traduzido em '''Left Joins''' ou Inserts/Updates/Deletes a medida que a entidade é persistida. | |||
{{nota|Visualização do Mapeamento|Durante o processo de Debug, é possível visualizar a tabela desse mapeamento através do método: | |||
<pre>BISDAO.dumpDAOMap(map)</pre> | |||
O conteúdo retornado é semelhando ao exibido abaixo neste documento, e pode ser verificado usando a inspeção de variável de dentro do BISDAO. O conteúdo retornado pode ser colado no Notepad para uma melhor visualização.}} | |||
Aqui temos um exemplo de mapeamento criado ao tentar buscar um objeto '''BISUserVO''' incluindo as empresas '''BISCompanyVO''': | |||
[[File:AssociacaoNN.png|center|frame|Associação ManyToMany entre BISCompanyVO e BISUserVO]] | |||
<pre> | |||
MAPEAMENTO DAS ENTIDADES | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
Path Schema.Table Alias Column Join JoinColumn Entity | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
bis_kernel.k_user t0 br.com.biserp.kernel.services.security.vo.BISUserVO | |||
.companies bis_kernel.k_user_company t1 idk_user t0 id null | |||
companies bis_kernel.k_company t2 id t1 idk_company br.com.biserp.kernel.vo.BISCompanyVO | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
MAPEAMENTO DOS ATRIBUTOS | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
Path Field Schema.Table Column | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
id (t0) bis_kernel.k_user id | |||
user (t0) bis_kernel.k_user user | |||
password (t0) bis_kernel.k_user password | |||
fullName (t0) bis_kernel.k_user fullName | |||
nickname (t0) bis_kernel.k_user nickname | |||
email (t0) bis_kernel.k_user email | |||
validatedKey (t0) bis_kernel.k_user validatedKey | |||
resetPasswordKey (t0) bis_kernel.k_user resetPasswordKey | |||
companies id (t2) bis_kernel.k_company id | |||
companies dbSchema (t2) bis_kernel.k_company dbSchema | |||
companies name (t2) bis_kernel.k_company name | |||
companies fullName (t2) bis_kernel.k_company fullName | |||
companies tradingName (t2) bis_kernel.k_company tradingName | |||
companies cnpj (t2) bis_kernel.k_company cnpj | |||
companies addressStreet (t2) bis_kernel.k_company addressStreet | |||
companies addressNumber (t2) bis_kernel.k_company addressNumber | |||
companies addressComplement (t2) bis_kernel.k_company addressComplement | |||
companies neighborhood (t2) bis_kernel.k_company neighborhood | |||
companies cep (t2) bis_kernel.k_company cep | |||
companies cityVO (t2) bis_kernel.k_company idk_locationCity | |||
companies phone (t2) bis_kernel.k_company phone | |||
companies email (t2) bis_kernel.k_company email | |||
companies ieType (t2) bis_kernel.k_company ieType | |||
companies regimeICMS (t2) bis_kernel.k_company regimeICMS | |||
companies ie (t2) bis_kernel.k_company ie | |||
companies taxsystem (t2) bis_kernel.k_company taxsystem | |||
companies spedPerfil (t2) bis_kernel.k_company spedPerfil | |||
companies spedActivityType (t2) bis_kernel.k_company spedActivityType | |||
companies contName (t2) bis_kernel.k_company contName | |||
companies contCPF (t2) bis_kernel.k_company contCPF | |||
companies contCRC (t2) bis_kernel.k_company contCRC | |||
companies contCNPJ (t2) bis_kernel.k_company contCNPJ | |||
companies contAddressStreet (t2) bis_kernel.k_company contAddressStreet | |||
companies contAddressNumber (t2) bis_kernel.k_company contAddressNumber | |||
companies contAddressComplement (t2) bis_kernel.k_company contAddressComplement | |||
companies contNeighborhood (t2) bis_kernel.k_company contNeighborhood | |||
companies contCep (t2) bis_kernel.k_company contCep | |||
companies contLocationCityVO (t2) bis_kernel.k_company idContk_locationCity | |||
companies contPhone (t2) bis_kernel.k_company contPhone | |||
companies contEmail (t2) bis_kernel.k_company contEmail | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
</pre> | |||
No mapeamento acima podemos ver duas sessões: a primeira que cria o mapeamento entre as entidades e as tabelas e a segunda que cria o mapeamento dos atributos e das colunas. | |||
A primeira tabela mapeada é a tabela da entidade para a qual o BISDAO foi criado. Neste caso a entidade BISUserVO, que utiliza a tabela k_user do schema bis_kernel. Ambas as informações retiradas das Annotation @BISDAO da entidade. A primeira tabela sempre recebe o alias '''t0'''. As próximas tabelas receberam o alias '''tN''', onde N é um número incremental, conforma as novas conexões forem criadas no map. | |||
''Considera a linha 3 agora, a linha 2 será explicada na sequência:'' As entidade BISUserVO e BISCompanyVO tem uma relação entre si e o BISDAO precisa buscar seu relacionamento para completar o objeto. Como partimos do Objeto BISUserVO, e as empresas estão na propriedade "companies" do objeto, a tabela do objeto BISCompanyVO recebe o valor "companies" na coluna de "Path". Como não é a tabela principal, este mapeamento recebeu também os valores "Column", "Join" e "JoinColumn", que são usadas para saber como conectar uma tabela na outra, sendo: | |||
* '''Column''' - Coluna da própria tabela que é utilizada para realizar a conexão com a coluna da outra tabela | |||
* '''Join''' - Nome da outra tabela à qual essa será associada. | |||
* '''JoinColumn''' - Coluna da tabela de "join" que é utilizada para realizar a conexão. | |||
Escrevendo como se fosse em uma condição do SQL seria algo como '''"... LEFT JOIN <Schema.Table> <Alias> ON <Alias>.<Column> = <Join>.<JoinColumn> ..."''' | |||
''Voltando à linha 2:'' No nosso exemplo é necessário notar que outro mapeamento de tabela foi criado. Isso ocorre porque o relacionamento entre BISUserVO e BISCompanyVO é N:N, e demanda uma "tabela de Join". Sempre em relacionamentos de N:N por existir uma tabela intermediária, esse mapeamento é gerado automaticamente. Ele recebe o mesmo "Path" que a tabela final receberia, mas é precedido de um '.'. Esse '.' tem a finalidade de avisar todos que forem utilizar o mapeamento (como na hora de montar o retorno do banco de dados) que essa tabela não tem uma entidade relacionada, e que seu conteúdo (suas colunas) não são atribuídas em nenhuma entidade. | |||
Na segunda parte do mapeamento é possível verificar os atributos da entidade e as colunas da tabela. note que o primeiro bloco tem o "Path" vazio. Isso indica que o "Field" pertence diretamente à entidade principal. No segundo bloco temos mapeamentos cujo "Path" está definido como "companies", isso quer dizer que do objeto principal, temos que recuperar o objeto dentro do atributo "companies" (que pode ser uma lista ou map) e então colocar os valores dos campos. A medida que objetos vão sendo relacionados em cadeia, o atributo Path receberá o caminho completo até chegar no objeto correto para criar as condições ou realizar as operações no banco de dados. | |||
Caso um objeto tenha mais de um relacionamento com a mesma tabela, a mesma tabela aparecerá mais de uma vez nos mapeamentos mas com Alias diferentes, e daí para frente seus conteúdos não se misturam mesmo entando fisicamente na mesma tabela. Por isso no mapeamento de atributos, não temos apenas as tabelas, mas também o Alias à qual este atributo está associado. | |||
== BISMetaCollection == | |||
A BISMetaCollection é utilizada quando temos uma coleção de valores simples, isto é, que não são outros objetos (VO). Como uma lista de Strings, Longs, etc. Seja em uma lista ordenada ou não, ou uma map. | |||
Nestes casos temos uma tabela auxiliar para colocar a coleção de valores, bem como o índice de ordem ou a chave da Map, como no caso do SchedulerVO e suas propriedades. A tabela para salvar os dados ficou como na imagem abaixo: | |||
[[File:BISMetaCollectionTable.png|center|Exemplo das tabelas para salvar a BISMetaCollection do SchedulerVO]] | |||
Uma vez criada as tabelas e declarado os objetos, o mapeamento criado pelo BISDAO fica da seguinte maneira: | |||
<pre> | |||
MAPEAMENTO DAS ENTIDADES | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
Path Schema.Table Alias Column Join JoinColumn Entity | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
bis_kernel.k_scheduler t0 br.com.biserp.kernel.services.scheduler.vo.SchedulerVO | |||
@properties bis_kernel.k_schedulerPropertyt1 idk_scheduler t0 id null | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
MAPEAMENTO DOS ATRIBUTOS | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
Path Field Schema.Table Column | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
id (t0) bis_kernel.k_scheduler id | |||
properties@ (t1) bis_kernel.k_schedulerProperty property | |||
properties@fk (t1) bis_kernel.k_schedulerProperty idk_scheduler | |||
properties@keyColumn (t1) bis_kernel.k_schedulerProperty key | |||
idKey (t0) bis_kernel.k_scheduler idKey | |||
taskClass (t0) bis_kernel.k_scheduler taskClass | |||
scheduleTime (t0) bis_kernel.k_scheduler scheduleTime | |||
lateExecution (t0) bis_kernel.k_scheduler lateExecution | |||
lastExecution (t0) bis_kernel.k_scheduler lastExecution | |||
repeatFrequency (t0) bis_kernel.k_scheduler repeatFrequency | |||
timeToRepeat (t0) bis_kernel.k_scheduler timeToRepeat | |||
recurrence (t0) bis_kernel.k_scheduler recurrence | |||
monthlyRepeatByDayOfMonth (t0) bis_kernel.k_scheduler monthlyRepeatByDayOfMonth | |||
stopDate (t0) bis_kernel.k_scheduler stopDate | |||
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | |||
</pre> | |||
Note que foi criado o mapeamento da tabela da collection mas o Path recebeu um prefixo de "@". Similar ao prefixo "." das tabelas de N:N o "@" tem a finalidade indicar que a tabela não respeita as regras das tabelas de entidades BISVO (como ter obrigatóriamente a PK como BigInt e chamada "id"). | |||
O restante das informações se referem as mesmas informações criadas para as tabelas de outras entidades. E será utilizada para realizar os Joins e cadastros na tabela. | |||
Já na sessão de atributos, podemos agora notar mais diferenças. Primeiro, na linha 2, o atributo "properties" que refere-se à lista de valores recebeu um sufixo "@". Esse sufixo tem a finalidade de indicar que é um atributo de lista, que receberá uma coleção/map de valores. Note que o Path continua "" já que o atributo pertente ao objeto raiz, apenas o sufixo "@" é que indica que teremos a MetaCollection. Porém, apesar do path, note que o atributo está mapeado na tabela auxiliar e não na tabela do objeto raiz. | |||
Na linha 3 observamos outro atributo auxiliar. Trata-se do mesmo atributo "properties" mas desta vez com um sufixo "@fk". Este sufixo tem a finalidade apenas de mapear a coluna da tabela auxiliar onde encontramos o ID do objeto pai, para que possamos monta-lo adequadamente. | |||
Temos ainda na linha 4 o mesmo atributo "properties" mas agora com o sufixo "@keyColumn". Também tem apenas a finalidade de mapear a coluna da tabela auxiliar que será utilizada como chave da Map. | |||
Por fim, caso não seja uma Map, mas sim uma lista ordenada podemos ter ao invés da "@keyColumn" o prefixo "@sortColumn". E terá a finalidade de mapear a coluna da tabela auxiliar onde encontramos o índice do objeto para saber onde posiciona-lo na MetaCollection. |
Edição atual tal como às 01h26min de 20 de maio de 2019
A persistência do BIS é automatizada como um sistema de ORM próprio chamado de BISDAO. Embora não seja tão maleável quanto os sistemas já consolidados no mercado, tem ótima performance, é melhor adaptado ao Framework do BIS e por não fazer injeção de código permite que VOs e métodos de persistência customizados sejam alterados por hot-deploy.
O principal objetivo do BISDAO é receber os VOs e persisti-lo (inserindo/atualizando), exclui-lo ou encontra-los no banco de dados automaticamente. Abstraindo a questão objeto x relacional do banco de dados, e diminuindo (ou eliminando na grande maioria dos casos) a necessidade de implementação códigos SQL pelo desenvolvedor.
Regras do Funcionamento
- Embora utilize os conceitos do banco de dados, não segue os padrões definidos no JPA. Assim, nenhuma annotation do JPA é utilizada nos VOs do BIS.
- O BISDAO manipula os VOs automaticamente. E não aceita nenhum outro tipo de objeto, isto é, para ser persistido é obrigatório que a entidade seja descendente do BISVO.
Estrutura do Banco de Dados
O BIS é uma plataforma que suporta múltiplas empresas sendo manipuladas pela mesmas instância. Assim um mesmo servidor e mesmo banco de dados será utilizado para gerenciar várias empresas. Para isso o sistema utilizará vários "schemas" (ou catálogos) do banco de dados, sendo:
- bis_kernel - schema onde ficam as tabelas de uso geral do sistema. Como o cadastro das empresas presentes, dos usuários de sistema, e outras tabelas de dados comuns a todas as empresas, como tabelas de CEP, e outros dados que não pertencem a uma única empresa.
- bis_<empresa> - com este nome deve existir um schema para cada empresa que o sistema gerencia. Isto é, para cada empresa que o BIS atender, um novo schema é criado para armazenar os dados específicos da empresa, como itens/produtos sendo vendidos, documentos fiscais, etc.
Configuração das FK
Ao criar a associação entre as tabelas do banco de dados devemos seguir as seguintes regras para o bom funcionamento do BISDAO:
Relacionamento tipo Associação
- No relacionamento não obrigatório devemos colocar as opções ON DELETE SET TO NULL (nos relacionamentos 1:1 ou 1:N) e ON DELETE CASCADE (nos relacionamentos N:N, para que se exclua o registro na tabela de join).
- O BISDAO não faz essa atualização para NULL para desmanchar o relacionamento antes de excluir o objeto. A ausência dessa configuração fará com que o objeto não possa ser excluído pelo BIS quando utilizado por outro objeto.
- No relacionamento obrigatório devemos colocar as opções ON DELETE RETRICT. Nos relacionamentos N:N podemos colocar para "restringir" de um lado mas para "cascata" de acordo com a condição de obrigatoriedade do relacionamento.
- Como o relacionamento é obrigatório (dependente) para a contra parte, a deleção deve ser restringida de propósito. Isso porque o BISDAO não procura objetos que dependam deste antes de excluir. O Banco de Dados fica responsável por restringir essa operação.
Relacionamento tipo Composição
- No caso de composição devemos sempre definir a opção ON DELETE CASCADE já que o objeto filho não existe sem o pai e não deve restringir a exclusão do pai.
![]() |
|
![]() |
|
![]() |
|
Relacionamento Entre Objetos
Os relacionamentos entre objetos serão declarados de acordo com o "tipo do relacionamento" constituído entre eles para que o BISDAO saiba como proceder quando for atualizar, inserir ou excluir os objetos. Entender o relacionamento entre os dois define a boa arquitetura ao criar os objetos:
Associação
O tipo de relacionamento Associação é utilizando quando ambos os objetos existem separadamente, mesmo que não tenham vínculos. Por exemplo:
- Aluno x Curso - Tanto Aluno quando Curso existem estando o aluno matriculado no curso ou não. Um curso pode existir sem ter nenhum aluno matriculado, bem como um Aluno pode existir sem estar matriculado em nenhum curto.
Para o BISDAO, esse tipo de relacionamento exige que a contra-parte já exista no banco de dados, ou seja já tenha um ID. A contra parte nunca é manipulada junto com este objeto, ou seja:
- Exclusão - O objeto da contra-parte não é excluído junto, apenas a associação é desfeita.
- Inclusão - Em caso de inclusão, o BISDAO espera que os objetos associados já tenham um ID. Pois eles não serão incluídos junto, apenas será criada uma associação.
- Alteração - Em caso de alteração o objeto será comparado com o atual no banco de dados. Objetos que não estejam mais presentes no objeto sendo persistido, terão sua associação removida, novos objetos terão associação criada. A contra-parte nunca será excluída, e nem criada.
Composição
O relacionamento do tipo composição indica que o objeto associação é uma "extensão" deste objeto. Ou seja, ele faz parte do objeto principal, e como tal será manipulando junto com o objeto pai. Por exemplo:
- Pessoas x Endereços da Pessoa - Pessoas pode existir sem ter um endereço, já o endereço da pessoa não existe sem a pessoa. Neste caso, "Endereços da Pessoa" é parte do objeto pai e será manipulado junto com ele.
Para o BISDAO a contra-parte pode ou não existir no banco de dados nos casos de alteração do objeto pai, mas no caso de inclusão do pai o objeto filho não deve ter ID (ou seja, não existe no banco). Mesmo que Pessoas diferentes tenham o mesmo Endereço, o BIS não permitirá compartilhar o mesmo objeto. Uma vez que a definição de composição não permite que o "reaproveitamento" do objeto. Para isso Endereço de Pessoa teria de ser uma entidade autônoma (existir sem o Pessoas) e o relacionamento deveria ser o de Associação. Neste caso a contra-parte é manipulada junto com o pai:
- Exclusão - Quando o objeto pai é excluído os objetos filhos serão excluídos junto.
- Inclusão - Em caso de inclusão, os objetos filhos serão incluídos juntos e automaticamente associados ao objeto pai.
- Alteração - Em caso de alteração do objeto pai, novos objetos filhos serão incluídos e persistidos, objetos filhos que foram removidos do objeto serão excluídos automaticamente. Bem como as informações dos objetos filhos persistentes também serão atualizadas em cascata, isto é, caso esse objeto também tenha outros de composição ou associação, eles também serão atualizados.
Annotation @BISDAO
Toda entidade deve ter a Class Annotation @BISDAO para configurar a tabela a qual o objeto se refere.
![]() |
Exemplo @BISDAO
@BISDAO(schemaType = Schema.KERNEL, table = "k_company")
public class BISCompanyVO extends BISVO {
...
}
|
A annotation tem dois parâmetros:
- schemaType - Indica se a tabela pertence ao Schema do Kernel do BIS ou ao Schema da empresa.
- table - Indica o nome da tabela onde o conteúdo deste objeto é guardado.
Relacionamento Atributo do Objeto x Coluna do BD
Para que um atributo do objeto seja relacionado corretamente com uma coluna da tabela (especificada na Annotation @BISDAO) é necessário que o atributo tenha uma @BISMeta Annotations. Nela constarão várias informações sobre o atributo, incluindo a coluna. Caso o nome da coluna não seja especificado, o BISDAO assume que o nome da coluna é exatamente o mesmo nome do atributo, ou seja, caso o mesmo nome seja utilizado na coluna do banco quando no atributo do objeto, não é necessário especificar o atributo coluna na Annotation. Isso deixa o código menos poluído.
Mapeamento do Relacionamento
O mapeamento de todos os relacionamentos são feitos através da @BISMetaRelationshipField.
Associação 1:1
Associação 1:N

A associação 1:N do exemplo é unilateral, já que só o FileVO tem conhecimento do vínculo. A descrição do mapeamento feito no FileVO é a mesma utilizada em uma associação 1:1.
![]() |
FileVO
@BISMetaRelationshipField(column = "k_company_id", relationship = RelationshipTypes.ASSOCIATION, ...)
private BISCompanyVO companyVO = null;
|
Sendo os atributos:
- relationship - Definido como ASSOCIATION para indicar a associação (tanto para 1:N quanto 1:1).
- column - nome da coluna que tem o ID da entidade associada. Utilizado somente se a coluna com o ID estiver na tabela desta entidade.
- columnMapped - nome da coluna que tem o ID do objeto da contra-parte. Utilizado somente se a coluna com o ID desta entidade (FK) estiver na tabela da entidade associada.
- targetRelationship - Classe do objeto utilizado na contra-parte. Normalmente a mesma classe passada no "generics" da coleção. Quando não é uma coleção de objeto, este atributo pode ser omitido e será usado o próprio tipo do Field declarado na classe. Neste caso o BISCompanyVO.
Associação N:N

A associação N:N (Many To Many) exige uma tabela intermediária para gravar as associações. Nos objetos o relacionamento é feito da seguinte maneira:
![]() |
BISCompanyVO
@BISMetaRelationshipField(relationship = RelationshipTypes.MANY_TO_MANY, joinTable = "k_user_company", column = "k_company_id", columnMapped = "k_user_id", targetRelationship = BISUserVO.class, ...)
private List<BISUserVO> users = null;
|
![]() |
BISUserVO
@BISMetaRelationshipField(relationship = RelationshipTypes.MANY_TO_MANY, joinTable = "k_user_company", column = "k_user_id", columnMapped = "k_company_id", targetRelationship = BISCompanyVO.class, ...)
private List<BISCompanyVO> companies = null;
|
Sendo os atributos:
- relationship - Em ambas as entidades definido como MANY_TO_MANY para indicar a associação de N:N.
- joinTable - Nome da tabela de join entre as tabelas dos objetos.
- column - nome da coluna que tem o ID da entidade onde está a declaração.
- columnMapped - nome da coluna que tem o ID do objeto da contra-parte.
- targetRelationship - Classe do objeto utilizado na contra-parte. Normalmente a mesma classe passada no "generics" da coleção.
![]() |
|
Composição 1:1

A composição 1:1 tem basicamente a função de separar uma coleção de dados do objeto principal, podendo deixar o objeto com os dados principais mais leve. Ou separar uma coleção de dados não obrigatórios. No exemplo abaixo, separamos o conteúdo do arquivo (FileContentVO) dos dados do arquivo (FileVO). Assim quando precisamos recuperar as informações sobre os arquivos do banco não temos de obter todo o conteúdo do arquivo deixando uma conexão pesada e muitos dados na memória.
![]() |
FileVO
@BISMetaRelationshipField(columnMapped = "k_file_id", relationship = RelationshipTypes.COMPOSITION, ...)
private FileContentVO fileContentVO = null;
|
Sendo os atributos:
- relationship - Definido como COMPOSITION para indicar a composição (tanto para 1:N quanto 1:1).
- column - nome da coluna que tem o ID da entidade associada. Utilizado somente se a coluna com o ID estiver na tabela desta entidade.
- columnMapped - nome da coluna que tem o nosso ID na tabela da contra-parte. Utilizado somente se a coluna com o ID desta entidade (FK) estiver na tabela da entidade associada.
- targetRelationship - Classe do objeto utilizado na contra-parte. Normalmente a mesma classe passada no "generics" da coleção. Quando não é uma coleção de objeto, este atributo pode ser omitido e será usado o próprio tipo do Field declarado na classe. Neste caso o FileContentVO.
![]() |
FileContentVO
@BISMetaRelationshipField(relationship = RelationshipTypes.PARENT_ASSOCIATION, column = "k_file_id")
private FileVO fileVO = null;
|
Sendo os atributos:
- relationship - Definido como PARENT_ASSOCIATION para indicar que esta entidade é a filha de uma composição (objeto submisso) e que este field se relaciona com o objeto pai.
- column - nome da coluna que tem o ID da entidade associada. Utilizado somente se a coluna com o ID estiver na tabela desta entidade.
- columnMapped - nome da coluna que tem o nosso ID na tabela da contra-parte. Utilizado somente se a coluna com o ID desta entidade (FK) estiver na tabela da entidade associada.
- targetRelationship - Classe do objeto utilizado na contra-parte. Normalmente a mesma classe passada no "generics" da coleção. Quando não é uma coleção de objeto, este atributo pode ser omitido e será usado o próprio tipo do Field declarado na classe. Neste caso o FileVO.
Composição 1:N
Composição N:N
O BIS não permite esse tipo de composição. Isso porque esse relacionamento indica o reaproveitamento dos objetos filhos por outros pais. Neste caso o objeto filho deve ter sua "autonomia" e viver independente do pai. Casos como esses devem ser transformados em Associação N:N.
Implementação
O BISDAO quando tem seus métodos chamados, ele analisa a classe da entidade e a primeira coisa que ele faz é criar um objeto de mapeamento - o DAOMap.
O DAOMap gerado cria uma estrutura de mapeamento entre a entidade e a tabela, e em seguida entre os atributos da entidade e as colunas das tabelas. Ele também analisa os atributos marcamos dom a BISMetaRelationshipField e cria a estrutura de mapeamento entre as tabelas e as FKs, o que normalmente depois é traduzido em Left Joins ou Inserts/Updates/Deletes a medida que a entidade é persistida.
![]() |
|
Aqui temos um exemplo de mapeamento criado ao tentar buscar um objeto BISUserVO incluindo as empresas BISCompanyVO:

MAPEAMENTO DAS ENTIDADES -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Path Schema.Table Alias Column Join JoinColumn Entity -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bis_kernel.k_user t0 br.com.biserp.kernel.services.security.vo.BISUserVO .companies bis_kernel.k_user_company t1 idk_user t0 id null companies bis_kernel.k_company t2 id t1 idk_company br.com.biserp.kernel.vo.BISCompanyVO -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MAPEAMENTO DOS ATRIBUTOS -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Path Field Schema.Table Column -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- id (t0) bis_kernel.k_user id user (t0) bis_kernel.k_user user password (t0) bis_kernel.k_user password fullName (t0) bis_kernel.k_user fullName nickname (t0) bis_kernel.k_user nickname email (t0) bis_kernel.k_user email validatedKey (t0) bis_kernel.k_user validatedKey resetPasswordKey (t0) bis_kernel.k_user resetPasswordKey companies id (t2) bis_kernel.k_company id companies dbSchema (t2) bis_kernel.k_company dbSchema companies name (t2) bis_kernel.k_company name companies fullName (t2) bis_kernel.k_company fullName companies tradingName (t2) bis_kernel.k_company tradingName companies cnpj (t2) bis_kernel.k_company cnpj companies addressStreet (t2) bis_kernel.k_company addressStreet companies addressNumber (t2) bis_kernel.k_company addressNumber companies addressComplement (t2) bis_kernel.k_company addressComplement companies neighborhood (t2) bis_kernel.k_company neighborhood companies cep (t2) bis_kernel.k_company cep companies cityVO (t2) bis_kernel.k_company idk_locationCity companies phone (t2) bis_kernel.k_company phone companies email (t2) bis_kernel.k_company email companies ieType (t2) bis_kernel.k_company ieType companies regimeICMS (t2) bis_kernel.k_company regimeICMS companies ie (t2) bis_kernel.k_company ie companies taxsystem (t2) bis_kernel.k_company taxsystem companies spedPerfil (t2) bis_kernel.k_company spedPerfil companies spedActivityType (t2) bis_kernel.k_company spedActivityType companies contName (t2) bis_kernel.k_company contName companies contCPF (t2) bis_kernel.k_company contCPF companies contCRC (t2) bis_kernel.k_company contCRC companies contCNPJ (t2) bis_kernel.k_company contCNPJ companies contAddressStreet (t2) bis_kernel.k_company contAddressStreet companies contAddressNumber (t2) bis_kernel.k_company contAddressNumber companies contAddressComplement (t2) bis_kernel.k_company contAddressComplement companies contNeighborhood (t2) bis_kernel.k_company contNeighborhood companies contCep (t2) bis_kernel.k_company contCep companies contLocationCityVO (t2) bis_kernel.k_company idContk_locationCity companies contPhone (t2) bis_kernel.k_company contPhone companies contEmail (t2) bis_kernel.k_company contEmail --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
No mapeamento acima podemos ver duas sessões: a primeira que cria o mapeamento entre as entidades e as tabelas e a segunda que cria o mapeamento dos atributos e das colunas.
A primeira tabela mapeada ?é a tabela da entidade para a qual o BISDAO foi criado. Neste caso a entidade BISUserVO, que utiliza a tabela k_user do schema bis_kernel. Ambas as informações retiradas das Annotation @BISDAO da entidade. A primeira tabela sempre recebe o alias t0. As próximas tabelas receberam o alias tN, onde N é um número incremental, conforma as novas conexões forem criadas no map.
Considera a linha 3 agora, a linha 2 será explicada na sequência: As entidade BISUserVO e BISCompanyVO tem uma relação entre si e o BISDAO precisa buscar seu relacionamento para completar o objeto. Como partimos do Objeto BISUserVO, e as empresas estão na propriedade "companies" do objeto, a tabela do objeto BISCompanyVO recebe o valor "companies" na coluna de "Path". Como não é a tabela principal, este mapeamento recebeu também os valores "Column", "Join" e "JoinColumn", que são usadas para saber como conectar uma tabela na outra, sendo:
- Column - Coluna da própria tabela que é utilizada para realizar a conexão com a coluna da outra tabela
- Join - Nome da outra tabela à qual essa será associada.
- JoinColumn - Coluna da tabela de "join" que é utilizada para realizar a conexão.
Escrevendo como se fosse em uma condição do SQL seria algo como "... LEFT JOIN <Schema.Table> <Alias> ON <Alias>.<Column> = <Join>.<JoinColumn> ..."
Voltando à linha 2: No nosso exemplo é necessário notar que outro mapeamento de tabela foi criado. Isso ocorre porque o relacionamento entre BISUserVO e BISCompanyVO é N:N, e demanda uma "tabela de Join". Sempre em relacionamentos de N:N por existir uma tabela intermediária, esse mapeamento é gerado automaticamente. Ele recebe o mesmo "Path" que a tabela final receberia, mas é precedido de um '.'. Esse '.' tem a finalidade de avisar todos que forem utilizar o mapeamento (como na hora de montar o retorno do banco de dados) que essa tabela não tem uma entidade relacionada, e que seu conteúdo (suas colunas) não são atribuídas em nenhuma entidade.
Na segunda parte do mapeamento é possível verificar os atributos da entidade e as colunas da tabela. note que o primeiro bloco tem o "Path" vazio. Isso indica que o "Field" pertence diretamente à entidade principal. No segundo bloco temos mapeamentos cujo "Path" está definido como "companies", isso quer dizer que do objeto principal, temos que recuperar o objeto dentro do atributo "companies" (que pode ser uma lista ou map) e então colocar os valores dos campos. A medida que objetos vão sendo relacionados em cadeia, o atributo Path receberá o caminho completo até chegar no objeto correto para criar as condições ou realizar as operações no banco de dados.
Caso um objeto tenha mais de um relacionamento com a mesma tabela, a mesma tabela aparecerá mais de uma vez nos mapeamentos mas com Alias diferentes, e daí para frente seus conteúdos não se misturam mesmo entando fisicamente na mesma tabela. Por isso no mapeamento de atributos, não temos apenas as tabelas, mas também o Alias à qual este atributo está associado.
BISMetaCollection
A BISMetaCollection é utilizada quando temos uma coleção de valores simples, isto é, que não são outros objetos (VO). Como uma lista de Strings, Longs, etc. Seja em uma lista ordenada ou não, ou uma map.
Nestes casos temos uma tabela auxiliar para colocar a coleção de valores, bem como o índice de ordem ou a chave da Map, como no caso do SchedulerVO e suas propriedades. A tabela para salvar os dados ficou como na imagem abaixo:

Uma vez criada as tabelas e declarado os objetos, o mapeamento criado pelo BISDAO fica da seguinte maneira:
MAPEAMENTO DAS ENTIDADES -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Path Schema.Table Alias Column Join JoinColumn Entity -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- bis_kernel.k_scheduler t0 br.com.biserp.kernel.services.scheduler.vo.SchedulerVO @properties bis_kernel.k_schedulerPropertyt1 idk_scheduler t0 id null -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MAPEAMENTO DOS ATRIBUTOS -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Path Field Schema.Table Column -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- id (t0) bis_kernel.k_scheduler id properties@ (t1) bis_kernel.k_schedulerProperty property properties@fk (t1) bis_kernel.k_schedulerProperty idk_scheduler properties@keyColumn (t1) bis_kernel.k_schedulerProperty key idKey (t0) bis_kernel.k_scheduler idKey taskClass (t0) bis_kernel.k_scheduler taskClass scheduleTime (t0) bis_kernel.k_scheduler scheduleTime lateExecution (t0) bis_kernel.k_scheduler lateExecution lastExecution (t0) bis_kernel.k_scheduler lastExecution repeatFrequency (t0) bis_kernel.k_scheduler repeatFrequency timeToRepeat (t0) bis_kernel.k_scheduler timeToRepeat recurrence (t0) bis_kernel.k_scheduler recurrence monthlyRepeatByDayOfMonth (t0) bis_kernel.k_scheduler monthlyRepeatByDayOfMonth stopDate (t0) bis_kernel.k_scheduler stopDate --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Note que foi criado o mapeamento da tabela da collection mas o Path recebeu um prefixo de "@". Similar ao prefixo "." das tabelas de N:N o "@" tem a finalidade indicar que a tabela não respeita as regras das tabelas de entidades BISVO (como ter obrigatóriamente a PK como BigInt e chamada "id").
O restante das informações se referem as mesmas informações criadas para as tabelas de outras entidades. E será utilizada para realizar os Joins e cadastros na tabela.
Já na sessão de atributos, podemos agora notar mais diferenças. Primeiro, na linha 2, o atributo "properties" que refere-se à lista de valores recebeu um sufixo "@". Esse sufixo tem a finalidade de indicar que é um atributo de lista, que receberá uma coleção/map de valores. Note que o Path continua "" já que o atributo pertente ao objeto raiz, apenas o sufixo "@" é que indica que teremos a MetaCollection. Porém, apesar do path, note que o atributo está mapeado na tabela auxiliar e não na tabela do objeto raiz.
Na linha 3 observamos outro atributo auxiliar. Trata-se do mesmo atributo "properties" mas desta vez com um sufixo "@fk". Este sufixo tem a finalidade apenas de mapear a coluna da tabela auxiliar onde encontramos o ID do objeto pai, para que possamos monta-lo adequadamente.
Temos ainda na linha 4 o mesmo atributo "properties" mas agora com o sufixo "@keyColumn". Também tem apenas a finalidade de mapear a coluna da tabela auxiliar que será utilizada como chave da Map.
Por fim, caso não seja uma Map, mas sim uma lista ordenada podemos ter ao invés da "@keyColumn" o prefixo "@sortColumn". E terá a finalidade de mapear a coluna da tabela auxiliar onde encontramos o índice do objeto para saber onde posiciona-lo na MetaCollection.