terça-feira, 17 de outubro de 2017

Removendo um elemento de uma Collection durante um laço "for" no Java

Erros simples as vezes no fazem perder tempo. As vezes temos uma coleção de objetos e em determinado momento precisamos percorrer essa coleção e remover alguns objetos de dentro dela, porém somos surpreendidos com uma mensagem de erro. O foreach não permite que façamos isso, pois ele acaba se perdendo na iteração.

Para resolver o problema, use o Iterator do java.

private void preencheCarroComCabecalho(
            final List<BtpCarro> lstBtpCarros, BtpCabecalho btpCabecalho)
{
        for (final Iterator<BtpCarros> iterator = lstBtpCarros
                .iterator(); iterator.hasNext();)
        {
            final BtpCarro btpCarro = iterator
                    .next();
            if ( btpCarros.getCarSeqCarro() != null )
            {
                btpCarros.setMarca(cabecalho.getMarca());
                btpCarros.setAno(cabecalho.getAno());
                btpCarros.setCor(cabecalho.getCor());
            }
            else
            {
      iterator.remove();
            }
        }
}

terça-feira, 10 de outubro de 2017

JPA - Quando usar uma Entidade ou um VO(DTO) na minha aplicação?


Bem, para começarmos vamos definir algumas nomenclaturas usadas em padrões de projeto de desenvolvimento.

Java Bean – Uma classe Java simples, com propriedades privadas, métodos de acesso, construtor padrão. Daí saem ideias como Bean CDI, ManagedBean JSF, etc. Também são chamados de POJO (Plain Old Java Object), que quer dizer nada mais nada menos que “bom e” Velho Objeto Java Padrão.

PO ou Entidade – Um bean Java que pode ser persistido no banco de dados. Também conhecido como PO (Persistent Object). Nomenclaturas muito usadas quando se trabalha com frameworks de persistência ORM como o Hibernate.  Trata-se de uma classe Java com propriedades privadas, métodos de acesso, construtor padrão, e métodos de identidade como equals e hashCode. Também devem implementar a interface Serializable. Podem ter sobrecarga de construtores e alguns métodos específicos da classe em alguns casos. Suas propriedades são persistidas no banco de dados.

VO (Value Object) – São objetos Java usados para guardar valores em memória, geralmente para usar na camada de visão, não sendo persistidos no banco de dados. Quando se há a necessidade de persistir parte de suas propriedades ou todas elas, elas são passadas para uma instancia de uma Entidade. São muito semelhantes (se não iguais) ao uso dos DTO’s (Data Transfer Object). Eu particularmente considero exatamente a mesma coisa.

         Dada a devida explicação, vemos que basicamente as Entidades tem suas propriedades persistidas no banco enquanto os VO’s são usados para exibir dados na camada de visão ou coisas semelhantes, desde que não envolva persistência.

A primeira pergunta é: Por quê?

Se eu posso usar o objeto que é a própria entidade para exibir dados na camada de visão ou fazer qualquer outra coisa, por que usar um VO ou DTO?

Basicamente por 2 motivos:

1.         A Entidade é engessada. Uma Entidade se comporta como uma estrutura engessada na hora das consultas, dificultando queries nativas, e impedindo de mesclar propriedades de Entidades diferentes. Te obriga a montar as Entidades que compõe a Entidade principal, o que pode trazer um grande encadeamento dependendo da complexidade das consultas.
2.         Melhora de performance. A Entidade pode ser muito grande e pesada, e você pode estar precisando apenas de 5 ou 10 propriedades, que podem inclusive serem montadas em Tipos Nativos do Java, diminuindo o grau de encadeamento destas, o que melhora a performance.

A segunda é: Quando usar VO e Quando usar Entidade?

Use Entidade quando os dados forem ser persistidos ou quando de fato você for carregar todas ou a maioria das propriedades, ou a entidade for simples.

Use VO quando for criar Relatórios, disponibilizar os dados em um WebService, quando quiser juntar dados de diferentes Entidades, etc.; e quando precisar fazer consultas nativas complexas.

A terceira e mais importante é: como usar?

E aí vem duas formas básicas:

1.         Quando for para carregar dados direto do banco, como estamos usando JPA, ele deve ser um Bean com as propriedades que você precisa, mesmo que de Tabelas distintas e de Entidades distintas, deve ser anotado com @Entity, da mesma forma que um Entidade qualquer mas sem especificar uma tabela e também deve ter uma propriedade que seja única para poder ser anotada com @Id. Possui um construtor padrão e geralmente um com todos os parâmetros. As propriedades são geralmente (Não é obrigatório) Tipos do Java (Integer, Long, String, Double, etc.) possuindo a anotação @Column indicando o nome dos campos usados na construção do SELECT, e os campos devem possuir seus getter’s e setter’s.

Exemplo:

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;

@Entity
public class VeiculoVO implements Serializable
{
    private static final long serialVersionUID = -5022603734460617635L;

    @Id
    @Column(name = "SEQ_VEICULO")

    private Long seqVeiculo;

    @Column(name = "LIC_SEQ_LICENCA")
    private Long licSeqLicenca;

    @Column(name = "VEI_DSC_PLACA")
    private String placa;

    @Column(name = "COR")
    private String cor;

    @Column(name = "MODELO")
    private String modelo;

    public VeiculoVO()
    {

    }


    public VeiculoVO(final Long seqVeiculo, final Long licSeqLicenca,
            final String placa, final String cor, final String modelo)
    {
        super();
        this.seqVeiculo = seqVeiculo;
        this.licSeqLicenca = licSeqLicenca;
        this.placa = placa;
        this.cor = cor;
        this.modelo = modelo;
    }

    public Long getSeqVeiculo()
    {
        return seqVeiculo;
    }

    public void setSeqVeiculo(final Long seqVeiculo)
    {
        this.seqVeiculo = seqVeiculo;
    }

    public Long getLicSeqLicenca()
    {
        return licSeqLicenca;
    }

    public void setLicSeqLicenca(final Long licSeqLicenca)
    {
        this.licSeqLicenca = licSeqLicenca;
    }

    public String getPlaca()
    {
        return placa;
    }

    public void setPlaca(final String placa)
    {
        this.placa = placa;
    }

    public String getCor()
    {
        return cor;
    }

    public void setCor(final String cor)
    {
        this.cor = cor;
    }

    public String getModelo()
    {
        return modelo;
    }

    public void setModelo(final String modelo)
    {
        this.modelo = modelo;
    }

}

Preenchendo o VO em uma classe de Negócio:

public List<VeiculoVO> getVeiculos()
{
  final StringBuilder sb = new StringBuilder();
  sb.append(" SELECT "
 + " (SELECT LIA.LIA_SEQ_LICENCA_AMBIENTAL FROM EMT_EMPRESA_TRANSBORDO EMT "
 + "     INNER JOIN LIA_LICENCA_AMBIENTAL LIA "
 + "    ON LIA.EMT_SEQ_EMPRESA = EMT.EMT_SEQ_EMPRESA "
 + "     INNER JOIN VEI_VEICULO VEI2 "
 + "    ON VEI2.LIA_SEQ_LICENCA_AMBIENTAL = LIA.LIA_SEQ_LICENCA_AMBIENTAL "
 + "     WHERE VEI2.VEI_DSC_PLACA = VEI.VEI_DSC_PLACA) AS LIC_SEQ_LICENCA, "
 + " VEI.VEI_SEQ_VEICULO AS SEQ_VEICULO, VEI.VEI_DSC_PLACA AS VEI_DSC_PLACA, "
 + " VEI.VEI_DSC_COR AS COR, VEI.VEI_DSC_MODELO AS MODELO "
 + " FROM EMT_EMPRESA_TRANSBORDO EMT "
 + " INNER JOIN LIA_LICENCA_AMBIENTAL LIA "
 + " ON LIA.EMT_SEQ_EMPRESA = EMT.EMT_SEQ_EMPRESA "
 + " INNER JOIN VEI_VEICULO VEI "
 + " ON VEI.LIA_SEQ_LICENCA_AMBIENTAL = LIA.LIA_SEQ_LICENCA_AMBIENTAL "
 + " INNER JOIN CON_CONTRATO CON "
 + " ON EMT.CON_SEQ_CONTRATO = CON.CON_SEQ_CONTRATO "
 + " INNER JOIN CLI_CLIENTE CLI "
 + " ON CON.CLI_SEQ_CLIENTE = CLI.CLI_SEQ_CLIENTE ");

  final Query query = entityManager.createNativeQuery(sb.toString(),
  VeiculoVO.class);


  return query.getResultList();
}

    
        Na Entidade Veiculo, a parte que está grifada de vermelho na verdade é uma Entidade chamada de Licenca, que guarda dados referentes a licença do veículo, mas no VO VeiculoVO só era necessário carregar o ID dessa entidade.


2.      Criando um VO em qualquer lugar do projeto para trazer facilidade e agilidade, populando as propriedades do VO a partir de outros VO’s ou de Entidades e até de entradas do usuário, sendo que em todos nesses casos, o VO pode dispensar as anotações e ser um simples POJO. Muitas vezes pode ser uma inner class para ajudar em regras da visão. Pode ser usada para agrupar as propriedades transientes, etc.

terça-feira, 3 de outubro de 2017

Mapeando chaves compostas com JPA - Hibernate

Nesse post eu vou falar sobre o mapeamento de chaves compostas no Hibernate.

É comum aparecer situações aonde precisamos de uma chave composta para garantir a unicidade de um registro, e o Hibernate trabalha isso de uma forma simples, tratando os campos que compõem a chave primária como um objeto separado embutido no objeto principal.

A classe que será embutida no objeto principal e que tem as propriedades que juntas compõem a chave primária deve ser anotada com @Embeddable. Essa classe não pode ser usada separada da classe principal, pois o Hibernate não trata ela como uma @Entity. Na classe principal, ao invés da anotação @id será usada a anotação @EmbeddedId.
 
Vou usar o exemplo da Cidade e UF pois acho simples de compreender. Vamos ver o código:

Vamos começar pela classe principal, que é a classe Município, o sequencial é a classe SeqMunicipio e o equals e hashCode são construídos em cima dele.

@Entity
public class Municipio {

    @EmbeddedId
    private SeqMunicipio seqMunicipio;

    @Column(name = "DSC_MUNICIPIO")
    private String dscMunicipio;

    @Column(name = "CEP")
    private Long cep;

    @ManyToOne
    @JoinColumn(name = "COD_UF", referencedColumnName = "COD_UF")
    private UnidadeFederacao codUF;

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ( ( seqMunicipio == null ) ? 0 : seqMunicipio.hashCode() );
        return result;
    }

    @Override
    public boolean equals( Object obj ) {
        if ( this == obj )
            return true;
        if ( obj == null )
            return false;
        if ( getClass() != obj.getClass() )
            return false;
        Municipio other = (Municipio) obj;
        if ( seqMunicipio == null ) {
            if ( other.seqMunicipio != null )
                return false;
        } else if ( !seqMunicipio.equals( other.seqMunicipio ) )
            return false;
        return true;
    }
   
}

Agora vamos a classe que contém a chave composta. Ela contém a serialização, o equals e o hashCode, um construtor vazio, e os métodos get’s and setter’s, além é claro das propriedades que compõem a chave composta.

@Embeddable
public class SeqMunicipio implements Serializable {

    private static final long serialVersionUID = 6576422530023818928L;

    @Column(name = "COD_MUNICIPIO")
    private Integer codMunicipio;

    @Column(name = "COD_UF")
    private Integer CodUnidadeFederacao;

    public SeqMunicipio() {
    }

    public SeqMunicipio( Integer codMunicipio, Integer codUnidadeFederacao ) {
        super();
        this.codMunicipio = codMunicipio;
        CodUnidadeFederacao = codUnidadeFederacao;
    }

    public Integer getCodMunicipio() {
        return codMunicipio;
    }

    public void setCodMunicipio( Integer codMunicipio ) {
        this.codMunicipio = codMunicipio;
    }

    public Integer getCodUnidadeFederacao() {
        return CodUnidadeFederacao;
    }

    public void setCodUnidadeFederacao( Integer codUnidadeFederacao ) {
        CodUnidadeFederacao = codUnidadeFederacao;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ( ( CodUnidadeFederacao == null ) ? 0 : CodUnidadeFederacao.hashCode() );
        result = prime * result + ( ( codMunicipio == null ) ? 0 : codMunicipio.hashCode() );
        return result;
    }

    @Override
    public boolean equals( Object obj ) {
        if ( this == obj )
            return true;
        if ( obj == null )
            return false;
        if ( getClass() != obj.getClass() )
            return false;
        SeqMunicipio other = (SeqMunicipio) obj;
        if ( CodUnidadeFederacao == null ) {
            if ( other.CodUnidadeFederacao != null )
                return false;
        } else if ( !CodUnidadeFederacao.equals( other.CodUnidadeFederacao ) )
            return false;
        if ( codMunicipio == null ) {
            if ( other.codMunicipio != null )
                return false;
        } else if ( !codMunicipio.equals( other.codMunicipio ) )
            return false;
        return true;
    }
}

A próxima classe é para vermos o uso de uma lista de objetos com id composto.

@Entity
public class UnidadeFederacao {

    @Id
    @Column(name = "COD_UF")
    private Integer codUF;

    @Column(name = "DSC_UF")
    private String dscUF;

    @Column(name = "SIGLA_UF")
    private String siglaUF;

    @OneToMany(mappedBy = "codUF", fetch = FetchType.LAZY)
    private List<Municipio> municipios;
}

Como eu faço para buscar um município? Supondo que o município 512 seja Fortaleza e o Estado 3 seja o Ceará faríamos assim:

SeqMunicipio seq = new SeqMunicipio(512,3);
Municipio m = entityManager.find(Municipio.class, seq);