RFWDAO
A classe RFWDAO é a principal classe do RFW ORM, seu objetivo principal é receber os RFWVOs e persisti-lo (inserindo/atualizando), exclui-lo ou encontra-los no banco de dados.
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 RFW.
- O RFWDAO 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 RFWVO.
Estrutura do Banco de Dados
O RFW suporta múltiplos schemas do banco de dados sendo manipuladas pela mesma instância do banco de dados e aplicação. Assim um mesmo servidor e mesmo banco de dados poderá ser utilizada para gerenciar várias instância do sistema. Para isso o sistema utilizará vários "schemas" (ou catálogos) do banco de dados.
Por exemplo, para cada VO você pode definir qual schame e tabela do banco de dados ele utilizará. E poderá, ainda, fazer com que que um VO acesse um schema diferente para cada usuário. Tendo, desta forma, os dados de cada usuário/sessão/cliente separado por schemas "gêmeos" no banco de dados, para armazenar dados pessoais como por exemplo o extrato bancário de cada um. E ainda assim ter VOs que utilizem um schema centralizado para buscar os dados que são únicos para todos, como uma tabela de CEPs de endereços.
Imagine um sistema para empresas, onde cada empresa é um cliente diferentes com dados particulares, sua divisão poderia ser:
- kernel - schema onde ficam as tabelas de uso geral do sistema. Como o cadastro das empresas presentes e nome dos seus schemas particulares, 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.
- <prefixo>_<empresa> - um schema para cada empresa gerenciada pelo sistema. Isto é, para cada empresa um novo schema é criado para armazenar os dados específicos da empresa, como itens/produtos sendo vendidos, documentos fiscais, extratos, 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 RFWDAO:
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 RFWDAO 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 RFW 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 RFWDAO 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 RFWDAO 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 RFWDAO, 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 RFWDAO 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 RFWDAO 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 RFW 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 alterado para 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 @RFWDAOAnnotation
Toda entidade deve ter a Class Annotation @RFWDAOAnnotation para configurar a tabela a qual o objeto se refere.
![]() |
Exemplo @RFWRFW |
@RFWDAAnnotationO(schemaType = Schema.KERNEL, table = "k_company")
public class RFWCompanyVO extends RFWVO {
...
}
|
A annotation tem dois parâmetros:
- schemaType - Indica se a qual schema a tabela pertence.
- table - Indica o nome da tabela deste objeto.
DAOResolver
O DAOResolver é uma interface disponibilizada pelo FrameWork para permitir uma intervenção na operação do RFWDAO de forma dinâmica.
Por exemplo, imagine o caso de uso em que o sistema tem diversas empresas para atender, e os dados de cada empresa é separado em um Schema do banco de dados diferentes, mas com a mesma estrutura. Digamos que sejam schemas com os nomes 'empresaA', 'empresaB', etc.
Dependendo da sessão do usuário, queremos obter os dados de um Schema específico (aquele da sua empresa). Utilizando apenas a annotation @RFWDAOAnnotation não conseguiríamos definir esses diferentes schemas para o mesmo objeto. Assim, nasce o DAOResolver!
Para utilizado é preciso criar uma implementação da interface DAOResolver. Seu método getSchema(...) será chamado toda vez que o RFWDAO precisar do Schema do objeto. Assim, no objeto que utiliza diversos schemas pode ser utilizado uma constante como "_COMPANYSCHEMA", e dentro do resolver, ao detectar esta constante verificar a sessão do usuário e retornar o schema da empresa adequado para a sessão.
![]() |
|
O DAOResolver tem atualmente 4 métodos:
getEntityType(...)
Este método permite que a classe da entidade seja substituída. A necessidade da implementação deste método é rara, e servirá para poquísimos casos. Mas imaginemos algum objeto (RFWVO) que seja fornecido pelo próprio framework. Como os VOs do serviço de Location que já oferecem componentes para a tela e outras funcionalidades. Mas por algum motivo a aplicação precisa de mais informações do que as fornecidas pelo objeto padrão do framework.
Assim, imagine que para isso os objetos Location do framework foram extendidos e a aplicação tenha seus próprios objetos. Quando algum componente do framework solicitar o objeto no RFWDAO, este método permitirá que a classe do objeto possa ser substituída por outra. Uma vez trocada, o RFWDAO passará a utilizar a nova classe daquele ponto em diante.
![]() |
|
getSchema(...) e getTable(...)
Por padrão o RFWDAO procura o Schema e a Tabela do objeto através da annotation @RFWDAOAnnotation escrita na classe. Mas em alguns momentos podemos querer um conteúdo mais dinâmico (trocando o schema ou a tabela conforme sessões e condições dos sistema, por exemplo). Ou mesmo informar o schema e a tabela a serem utilizados para objetos que não tem a annotation (como VOs do próprio RFW).
Para isso basta identificar o objeto sendo solicitado e retornar os valores desejados. Se algum valor for retornado ele será utilizado pelo RFWDAO, se sobrepondo as informações da annotation. Caso seja retornado nulo o RFWDAO seguirá com sua implementação padrão.
createInstance(...)
Este método intervêm na instanciação dos objetos pelo RFWDAO. Se implementado, este método será chamado sempre que o RFWDAO precisar instanciar um novo objeto para alocar o conteúdo do banco de dados. Ele pode ser útil para que seja possível a criação de objetos sem um construtor padrão (sem argumentos), ou caso haja a necessidade de instanciar uma classe descendente, e assim por diante.
getMetaRelationColumn(...), getMetaRelationColumnMapped(...) e getMetaRelationJoinTable(...)
Este três métodos permitem interferir nos atributos column, columnMapped e joinTable da RFWMetaRelationshipField encontrada nos elementos de persistência. Sua funcionalidade se assemelha as descritas anteriormente.
Ao persistir algum objeto que já seja fornecido pelo framework, e sem a possibilidade de fazer a definição diretamente no objeto, podemos utilizar estes métodos para corrigir/terminar a configuração da definição do relacionamento no banco de dados.
Ao implementar estes métodos deve-se verificar se é um objeto "de interesse" e retornar o atributo desejado. Caso não deseje realizar nenhuma intervenção basta retornar nulo para que o RFWDAO assuma sua implementação padrão (buscando dentro da Annotation).
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 @RFWDAOAnnotation) é necessário que o atributo tenha uma @RFWMetaAnnotations. Nela constarão várias informações sobre o atributo, incluindo a coluna. Caso o nome da coluna não seja especificado, o RFWDAO 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 @RFWMetaRelationshipField.
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 |
@RFWMetaRelationshipField(column = "k_company_id", relationship = RelationshipTypes.ASSOCIATION, ...)
private RFWCompanyVO 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 RFWCompanyVO.
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:
![]() |
RFWCompanyVO |
@RFWMetaRelationshipField(relationship = RelationshipTypes.MANY_TO_MANY, joinTable = "k_user_company", column = "k_company_id", columnMapped = "k_user_id", targetRelationship = RFWUserVO.class, ...)
private List<RFWUserVO> users = null;
|
![]() |
RFWUserVO |
@RFWMetaRelationshipField(relationship = RelationshipTypes.MANY_TO_MANY, joinTable = "k_user_company", column = "k_user_id", columnMapped = "k_company_id", targetRelationship = RFWCompanyVO.class, ...)
private List<RFWCompanyVO> 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 |
@RFWMetaRelationshipField(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 |
@RFWMetaRelationshipField(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 RFW 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
Quando o RFWDAO 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 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 RFWMetaRelationshipField e cria a estrutura de mapeamento entre as tabelas e as FKs, o que normalmente, posteriormente, é 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 RFWUserVO incluindo as empresas RFWCompanyVO:
MAPEAMENTO DAS ENTIDADES -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Path Schema.Table Alias Column Join JoinColumn Entity -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- rfw_kernel.k_user t0 br.com.rfw.kernel.services.security.vo.RFWUserVO .companies rfw_kernel.k_user_company t1 idk_user t0 id null companies rfw_kernel.k_company t2 id t1 idk_company br.com.rfw.kernel.vo.RFWCompanyVO -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MAPEAMENTO DOS ATRIBUTOS -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Path Field Schema.Table Column -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- id (t0) rfw_kernel.k_user id user (t0) rfw_kernel.k_user user password (t0) rfw_kernel.k_user password fullName (t0) rfw_kernel.k_user fullName nickname (t0) rfw_kernel.k_user nickname email (t0) rfw_kernel.k_user email validatedKey (t0) rfw_kernel.k_user validatedKey resetPasswordKey (t0) rfw_kernel.k_user resetPasswordKey companies id (t2) rfw_kernel.k_company id companies dbSchema (t2) rfw_kernel.k_company dbSchema companies name (t2) rfw_kernel.k_company name companies fullName (t2) rfw_kernel.k_company fullName companies tradingName (t2) rfw_kernel.k_company tradingName companies cnpj (t2) rfw_kernel.k_company cnpj companies addressStreet (t2) rfw_kernel.k_company addressStreet companies addressNumber (t2) rfw_kernel.k_company addressNumber companies addressComplement (t2) rfw_kernel.k_company addressComplement companies neighborhood (t2) rfw_kernel.k_company neighborhood companies cep (t2) rfw_kernel.k_company cep companies cityVO (t2) rfw_kernel.k_company idk_locationCity companies phone (t2) rfw_kernel.k_company phone companies email (t2) rfw_kernel.k_company email companies ieType (t2) rfw_kernel.k_company ieType companies regimeICMS (t2) rfw_kernel.k_company regimeICMS companies ie (t2) rfw_kernel.k_company ie companies taxsystem (t2) rfw_kernel.k_company taxsystem companies spedPerfil (t2) rfw_kernel.k_company spedPerfil companies spedActivityType (t2) rfw_kernel.k_company spedActivityType companies contName (t2) rfw_kernel.k_company contName companies contCPF (t2) rfw_kernel.k_company contCPF companies contCRC (t2) rfw_kernel.k_company contCRC companies contCNPJ (t2) rfw_kernel.k_company contCNPJ companies contAddressStreet (t2) rfw_kernel.k_company contAddressStreet companies contAddressNumber (t2) rfw_kernel.k_company contAddressNumber companies contAddressComplement (t2) rfw_kernel.k_company contAddressComplement companies contNeighborhood (t2) rfw_kernel.k_company contNeighborhood companies contCep (t2) rfw_kernel.k_company contCep companies contLocationCityVO (t2) rfw_kernel.k_company idContk_locationCity companies contPhone (t2) rfw_kernel.k_company contPhone companies contEmail (t2) rfw_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 RFWDAO foi criado. Neste caso a entidade RFWUserVO, que utiliza a tabela k_user do schema rfw_kernel. Ambas as informações retiradas das Annotation @RFWDAOAnnotation 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 RFWUserVO e RFWCompanyVO tem uma relação entre si e o RFWDAO precisa buscar seu relacionamento para completar o objeto. Como partimos do Objeto RFWUserVO, e as empresas estão na propriedade "companies" do objeto, a tabela do objeto RFWCompanyVO 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 RFWUserVO e RFWCompanyVO é 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.
RFWMetaCollection
A RFWMetaCollection é 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 RFWDAO fica da seguinte maneira:
MAPEAMENTO DAS ENTIDADES -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Path Schema.Table Alias Column Join JoinColumn Entity -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- rfw_kernel.k_scheduler t0 br.com.rfw.kernel.services.scheduler.vo.SchedulerVO @properties rfw_kernel.k_schedulerPropertyt1 idk_scheduler t0 id null -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- MAPEAMENTO DOS ATRIBUTOS -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Path Field Schema.Table Column -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- id (t0) rfw_kernel.k_scheduler id properties@ (t1) rfw_kernel.k_schedulerProperty property properties@fk (t1) rfw_kernel.k_schedulerProperty idk_scheduler properties@keyColumn (t1) rfw_kernel.k_schedulerProperty key idKey (t0) rfw_kernel.k_scheduler idKey taskClass (t0) rfw_kernel.k_scheduler taskClass scheduleTime (t0) rfw_kernel.k_scheduler scheduleTime lateExecution (t0) rfw_kernel.k_scheduler lateExecution lastExecution (t0) rfw_kernel.k_scheduler lastExecution repeatFrequency (t0) rfw_kernel.k_scheduler repeatFrequency timeToRepeat (t0) rfw_kernel.k_scheduler timeToRepeat recurrence (t0) rfw_kernel.k_scheduler recurrence monthlyRepeatByDayOfMonth (t0) rfw_kernel.k_scheduler monthlyRepeatByDayOfMonth stopDate (t0) rfw_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 RFWVO (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.
Utilização
Para utilizar o RFWDAO basta instanciar a classe passando seus atributos:
- DataSource responsável por entregar conexões sob demanda. Você deve criar o datasource de acordo com seu projeto, sendo J2EE ou uma aplicação stand alone.
- dialect Defina o dialeto de acordo com o banco de dados que esteja utilizando.
- resolver interface utilizada para que sejam requisitadas informações pelo RFWDAO para a aplicação. Por exemplo, solicita através desta interface o schema que deverá ser utilizado para cada objeto. Veja mais detalhes na documentação da interface.
Vejamos um exemplo:
![]() |
Criando o RFWDAO |
RFWDAO<MyVO> myDAO = new RFWDAO<MyVO>(MyVO.class, null, dataSource, SQLDialect.MySQL, daoResolver);
|
Com esse objeto RFWDAO temos acesso a manipular as entidades MyVO:
![]() |
Criando o RFWDAO |
MyVO myVO = myDAO.findUniqueMatch(myMO, null); //Busca uma ocorrência única de um objeto
...
MyVO myVO = myDAO.persist(myVO); //Persiste o objeto, inserindo se ele não tiver ID, atualizando se tiver ID.
|
Criando o DAOResolver
Vamos agora criar um exemplo de instância do RFWDAO passando uma instância do DAOResolver que para determinados VOs define um Schema de acordo com a sessão do usuário:
![]() |
Criando o RFWDAO |
RFWDAO<MyVO> myDAO = new RFWDAO<MyVO>(MyVO.class, null, dataSource, SQLDialect.MySQL, (entityType, entityDAOAnn) -> {
switch (entityDAOAnn.schema()) {
case "_sessionSchema":
return getUserSessionSchema(); // Método da aplicação para obter o nome do schema correto para essa sessão
default:
return entityDAOAnn.schema(); // Se não encontrou uma constante conhecida, utiliza o próprio schema definido no VO.
}
});
|
Vejamos agora o exemplo da definição dentro dos VO:
Definição do LocationVO:
![]() |
LocationVO utilizando o schema próprio |
@RFWDAOAnnotation(schema = "myDefaultSchema", table = "locationTable")
public class LocationVO extends RFWVO {
...
}
|
Definição do AccountVO:
![]() |
AcountVO utilizando o schema da sessão |
@RFWDAOAnnotation(schema = "_sessionSchema", table = "accountTable")
public class AccountVO extends RFWVO {
...
}
|
Note que nos VOs acima, o LocationVO utilizou um schema próprio, chamado de myDefaultSchema, enquanto que o AccountVO utilizou a definição batizada de _sessionSchema.
Até este momento não há nenhuma diferença no que o RFWDAO fará com essa informação. Para o LocationVO o RFWDAO procurará a tabela locationTable dentro do schema myDefaultSchema, e para o AccountVO, procurará a tabela accountTable dentro do schema _sessionSchema. Só que _sessionSchema não é um schema real no banco de dados, é apenas uma constante para que o DAOResolver encontre e troque pelo schema do usuário realizando a solicitação. Desta forma, a mesma instância da aplicação e memo VO acessa a cada solicitação dados exclusivos.
Recomendação da Factory
Como a instanciação do RFWDAO pode exigir muitas linhas de código além da chamada de alguns métodos particulares, como a obtenção de DataSource e a instância do DAOResolver, a recomendação é que a aplicação tenha uma classe de Factory para centralizar esse código e simplificar o código sempre que precisar criar um RFWDAO.
Veja a seguir o esqueleto de uma Factory sugerida:
![]() |
Sugestão de Factory para Instanciação do RFWDAO |
public class DAOFactory {
/**
* Construtor privado para classe estática
*/
private DAOFactory() {
}
/**
* Cria um RFWDAO que utiliza o Resolver padrão da aplicação para definir o Schema.<br>
*
* @param <VO> Definição genérica do objeto que extende RFWVO para a qual este RFWDAO estará focado.
* @param voClass Classe do objeto que extende RFWVO para a qual este RFWDAO estará focado.
* @return RFWDAO instanciado
* @throws RFWException Lançado em caso de falha na operação.
*/
public static <VO extends RFWVO> RFWDAO<VO> createDAO(Class<VO> voClass) throws RFWException {
// Implementação de um DAOResolver direto com um switch vazio para adaptação da aplicação.
// Note que se não tiver a necessidade de schemas dinâmicos na sua aplicação, você pode passar 'null' no DAOResolver.
// Se nenhum DAOResolver for passado para o RFWDAO, por padrão, ele utiliza a definição de schema do VO.
return new RFWDAO<VO>(voClass, null, getDataSource(), SQLDialect.MySQL, (entityType, entityDAOAnn) -> {
switch (entityDAOAnn.schema()) {
default:
return entityDAOAnn.schema();
}
});
}
private static DataSource getDataSource() throws RFWException {
// TODO Implementar criação do DataSource
return null;
}
}
|
Note que este é só um exemplo e que deve ser adaptado as necessidades da aplicação.
Outras Estruturas
RFWField
O objeto `RFWField` é uma classe fundamental dentro do framework para manipulação de campos de entidades em operações de banco de dados. Ele facilita a definição de campos de maneira dinâmica, permitindo operações como filtros, ordenações e agregações em consultas. Seu uso é comum em cenários onde se deseja manipular ou consultar dados no banco de forma flexível, sem a necessidade de consultas SQL escritas manualmente.
Com o `RFWField`, é possível realizar consultas utilizando funções do banco de dados como `SUM`, `DISTINCT`, `COALESCE`, entre outras, permitindo também consultas e operações mais livres, fora do modelo estrutural rígido do RFWDAO.
Função 'COUNT'
Para realizar uma consulta utilizando a função `COUNT` com o `RFWField`, você pode seguir o exemplo abaixo:
![]() |
Consulta com COUNT |
// Defina o campo utilizando a função COUNT
RFWField[] fields = new RFWField[] {
RFWField.count()
};
// Crie um MatchObject (MO) para filtrar os dados conforme necessário
RFWMO mo = new RFWMO();
mo.equal(UserVO_._user, "admin");
// Realize a consulta
List<Object[]> result = facade.findListEspecial(uuid, UserVO.class, fields, mo, null, null, null, null);
// O resultado conterá o total de registros que satisfazem as condições do MO
Long totalCount = (Long) result.get(0)[0];
|
![]() |
|
Função 'SUM'
Para realizar uma consulta utilizando a função `SUM` com o `RFWField`, você precisa especificar o campo a ser somado. Veja o exemplo abaixo:
![]() |
Consulta com SUM |
// Defina o campo utilizando a função SUM, passando o nome da coluna que deseja somar
RFWField[] fields = new RFWField[] {
RFWField.sum("total")
};
// Realize a consulta sem filtros específicos
List<Object[]> result = dao.findListEspecial(fields, null, null, null, null, null);
// O resultado conterá a soma de todos os valores da coluna especificada
BigDecimal totalSum = (BigDecimal) result.get(0)[0];
|
Função DISTINCT
A função `DISTINCT` é utilizada para retornar valores únicos, eliminando duplicações. Isso é útil em consultas onde você deseja evitar registros duplicados.
![]() |
Exemplo de consulta utilizando DISTINCT |
// Exemplo de consulta utilizando DISTINCT para buscar nomes de usuários únicos
// Defina o campo utilizando a função SUM, passando o nome da coluna que deseja somar
RFWField[] fields = new RFWField[] {
RFWField.distinct(UserVO_._sector)
};
// Montando o Meta Objeto para a consulta
RFWMO mo = new RFWMO();
//... seus filtros
// Realizando a consulta
List<Object[]> resultList = dao.findListEspecial(fields, mo, null, null, null, null);
|
Neste exemplo, o campo `"sector"` é consultado com a função `DISTINCT` aplicada, retornando apenas os nomes únicos encontrados no banco de dados.
Função MAXIMUM
![]() |
Exemplo de uso da função MAXIMUM |
// Defina o campo utilizando a função MAXIMUM, passando o nome da coluna que deseja obter o valor máximo
RFWField[] fields = new RFWField[] {
RFWField.maximun(UserVO_._salary)
};
// Montando o Meta Objeto para a consulta
RFWMO mo = new RFWMO();
//... adicione seus filtros aqui, se necessário
// Realizando a consulta
List<Object[]> resultList = dao.findListEspecial(fields, mo, null, null, null, null);
// O resultado conterá o valor máximo da coluna especificada
BigDecimal maxSalary = (BigDecimal) resultList.get(0)[0];
|
No exemplo acima, a função `MAXIMUM` é aplicada à coluna do atributo UserVO.salary para retornar o maior valor encontrado na consulta.
Função MIN
@TODO
Função AVG
@TODO
Função UPPER
@TODO
Função LOWER
@TODO
Função LENGTH
@TODO
Função TRIM
@TODO
Função SUBSTRING
@TODO
Função ABS
@TODO
Função ROUND
@TODO
Função CONCAT
@TODO