Mostrando postagens com marcador Hibernate. Mostrar todas as postagens
Mostrando postagens com marcador Hibernate. Mostrar todas as postagens

quarta-feira, 10 de março de 2021

JPA 2.1 - Criteria Builder, evitando query adicional causada por FetchType Lazy (lazy-loading)

 Hoje durante a utilização da api criteria para consultas dinâmicas enquanto realizava um curso, me deparei com uma coisa bem chata, no qual eu possuo 3 beans.
  • Estado
  • Cidade
  • Usuário
Ocorria o seguinte inconveniente, devido essa consulta ser usada em filtros decidi usar o CriteriaBuilder pela facilidade em criar  dinamicamente as consultas, porem todas as vezes que eu realizava uma consulta sempre recebia duas consultas adicionais, uma para Cidade e outra para Estado. E antes que me perguntem sim! marquei como lazy essas relações e não desejo nem quero que sejam JoinType Eager sempre, porem ao usar o CriteriaBuilder ele ignora completamente e volta a usar o lazy-loading.

  
    select
        cliente0_.codigo as codigo1_2_,
        cliente0_.cpf_cnpj as cpf_cnpj2_2_,
        cliente0_.email as email3_2_,
        cliente0_.cep as cep4_2_,
        cliente0_.codigo_cidade as codigo_11_2_,
        cliente0_.complemento as compleme5_2_,
        cliente0_.logradouro as logradou6_2_,
        cliente0_.numero as numero7_2_,
        cliente0_.nome as nome8_2_,
        cliente0_.telefone as telefone9_2_,
        cliente0_.tipo_pessoa as tipo_pe10_2_ 
    from
        cliente cliente0_ 
    where
        1=1 limit ?;

    select
        cidade0_.codigo as codigo1_1_0_,
        cidade0_.codigo_estado as codigo_e3_1_0_,
        cidade0_.nome as nome2_1_0_ 
    from
        cidade cidade0_ 
    where
        cidade0_.codigo=?;

    select
        estado0_.codigo as codigo1_3_0_,
        estado0_.nome as nome2_3_0_,
        estado0_.sigla as sigla3_3_0_ 
    from
        estado estado0_ 
    where
        estado0_.codigo=?

O que de fato não é nem de longe ideal para um bom desempenho, mas então oque fazer ? será que existe uma forma de incorporar na primeira query as duas adicionais ? E a resposta é sim! basta fazer o fetch ,  nas relações que deseja evitar as consultas adicionais, mesma coisa que fazemos no HQL.

   Root cliente = querie.from(Cliente.class);           
            
   cliente.fetch(Cliente_.ENDERECO)//Representa o endereço 
          .fetch(Endereco_.CIDADE, JoinType.LEFT)//Realiza o Fetch de Cliente com Cidade
          .fetch(Cidade_.ESTADO, JoinType.LEFT);  //Realiza o Fetch da Cidade com estado
  
A partir de agora a consulta gerada é a seguinte.
  
    select
        cliente0_.codigo as codigo1_2_0_,
        cidade1_.codigo as codigo1_1_1_,
        estado2_.codigo as codigo1_3_2_,
        cliente0_.cpf_cnpj as cpf_cnpj2_2_0_,
        cliente0_.email as email3_2_0_,
        cliente0_.cep as cep4_2_0_,
        cliente0_.codigo_cidade as codigo_11_2_0_,
        cliente0_.complemento as compleme5_2_0_,
        cliente0_.logradouro as logradou6_2_0_,
        cliente0_.numero as numero7_2_0_,
        cliente0_.nome as nome8_2_0_,
        cliente0_.telefone as telefone9_2_0_,
        cliente0_.tipo_pessoa as tipo_pe10_2_0_,
        cidade1_.codigo_estado as codigo_e3_1_1_,
        cidade1_.nome as nome2_1_1_,
        estado2_.nome as nome2_3_2_,
        estado2_.sigla as sigla3_3_2_ 
    from
        cliente cliente0_ 
    left outer join
        cidade cidade1_ 
            on cliente0_.codigo_cidade=cidade1_.codigo 
    left outer join
        estado estado2_ 
            on cidade1_.codigo_estado=estado2_.codigo 
    where
        1=1 limit ?

Espero ter ajudado pessoas que assim como eu tiveram muitos problemas,  para conseguir realizar esse simples procedimento assim como era feito no HQL.

terça-feira, 1 de outubro de 2019

JPA MAPEAMENTO MAP COM CHAVE ENUM E VALOR OBJECT


A baixo a descrição em código de como Mapear um objeto do tipo Map tendo como chave um Enum e valor uma Entidade que poderia ser qualquer outro Objeto

@Data @AllArgsConstructor @NoArgsConstructor @Builder
@Entity
@Table(schema = "gdf",name = "tb_VeiculoPneus")
 public
 class VeiculoPneus implements Serializable{

    @Id
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "CodVeiculo")
 private Veiculos codigoVeiculo;


    @OneToMany
    @JoinTable(name = "tb_VeiculoPosicaoPneu",schema = "gdf"
       ,uniqueConstraints = 
         @UniqueConstraint(name="UK_PNEU_VEICULOPOSICAOPNEU"
          ,columnNames={"CodPneu"})
       ,joinColumns= 
         @JoinColumn(name="CodVeiculoPneus"
          ,foreignKey= 
            @ForeignKey(name="FK_VEICULOPNEUS_VEICULOPOSICAOPNEU")
         )
       ,inverseJoinColumns=  
         @JoinColumn(name="CodPneu"
          ,foreignKey= 
            @ForeignKey(name="FK_PNEU_VEICULOSPOSICAOPNEU")
         ) 
    )
    @MapKeyEnumerated(EnumType.STRING)
    @MapKeyClass(PosicaoPneu.class)
    @MapKeyColumn(name ="CodPosicao")
 private Map<PosicaoPneu,Pneu> pneus;   

 }

Este mapeamento gera a seguinte saída SQL:

 create table gdf.tb_VeiculoPosicaoPneu
 (
    CodVeiculoPneus int not null
  , CodPneu         bigint not null
  , CodPosicao      varchar(255) not null
  , primary key (CodVeiculoPneus, CodPosicao)
        )
  
 alter table gdf.tb_VeiculoPosicaoPneu 
       add constraint UK_PNEU_VEICULOPOSICAOPNEU 
 unique (CodPneu)
 
 alter table gdf.tb_VeiculoPosicaoPneu 
       add constraint FK_PNEU_VEICULOSPOSICAOPNEU 
       foreign key (CodPneu )
       references gdf.tb_Pneu
    
 alter table gdf.tb_VeiculoPosicaoPneu 
       add constraint FK_VEICULOPNEUS_VEICULOPOSICAOPNEU 
       foreign key (CodVeiculoPneus) 
       references gdf.tb_VeiculoPneus

sábado, 19 de maio de 2012

B cannot be cast to java.sql.Blob

Bom dia!

   - Mais uma vez meus problemas me levam a aprender mais e mais, Amem!. Primeira vez que necessitei carregar uma imagem para um banco de dados, e claro eu nao sabia q é necessario um campo do tipo blob ou semelhantes.
 -  Entao segui alguns exemplos do guj, até que encontrei algo interessante e tentei. Porem ao tentar persistir os dados do banco tive um problema de Cast(Conversao) de um byte [] para um sql Blob, entao abaixo sintaxe de como fazer este cast.




  1. //Cria uma referencia a uma imagem ja transformada em Array de bytes
  2. byte [] imagem=imagem.getFoto()
  3. //Declara a variavel foto que seja uma variavel de instancia do objeto SerialBlob que recebe o Array
  4. Blob foto = new SerialBlob(imagem)

quarta-feira, 20 de abril de 2011

Mapeamento one-to-many Hibernate.

Boa Tarde


Pois, bem vou dividir como resolver um pequeno problema que tive que levou algumas semanas auhaua, bem apos ler em varios foruns, resolvi ir ler a documentação e fazer o tutorial disponivel na documentação, bem nao obtive muito sucesso, eu nao conseguiua salvar as coleções, sempre aparecia uma execessao , do tipo NullPointerException a qual na minha opniao e um saco, se alguem tentar traduzir saberá que se refere a algo que nao foi instanciado, nao foi criado nao tem referencia, ate que eu me recordei de uma pequena coisinha a se fazer quando se quer add dados a coleção diretamente a classe, abaixo o codigo.


  1. public class Parent {
  2.     private int id;
  3.     private String  nome;
  4.     private Set<Childrem> children;  
  5.     public int getId() {
  6.         return id;
  7.     }
  8.     public void setId(int id) {
  9.         this.id = id;
  10.     }
  11.     public String getNome() {
  12.         return nome;
  13.     }
  14.     public void setNome(String nome) {
  15.         this.nome = nome;
  16.     }
  17.     public Set<Childrem> getChildren() {
  18.         return children;
  19.     }
  20.     public void setChildren(Set<Childrem> children) {
  21.         this.children = children;
  22.     }

  1. public class Childrem {
  2.     private Parent parent_id;
  3.     private int id;
  4.     private String nomeChildrem;
  5.     public Childrem() {
  6.     }        
  7.     public Parent getParent_id() {
  8.         return parent_id;
  9.     }
  10.     public void setParent_id(Parent parent_id) {
  11.         this.parent_id = parent_id;
  12.     }
  13.     public String getNomeChildrem() {
  14.         return nomeChildrem;
  15.     }
  16.     public void setNomeChildrem(String nomeChildrem) {
  17.         this.nomeChildrem = nomeChildrem;
  18.     }
  19.     public int getId() {
  20.         return id;
  21.     }
  22.     public void setId(int id) {
  23.         this.id = id;
  24.     }
  25. }

Acredito que qualquer um saiba que ai estao as duas classes agora o mapeamento.


  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
  3. <hibernate-mapping>
  4.   <class name="Classes.Parent" >
  5.     <id name="id" >
  6.         <generator class="native" />
  7.     </id>
  8.     <property name="nome"/>
  9.     <set name="children" inverse="true"  cascade="all-delete-orphan">
  10.         <key column="parent_id" not-null="true"/>
  11.         <one-to-many class="Classes.Childrem" />
  12.     </set>
  13.   </class>
  14.   <class name="Classes.Childrem"><!--Classe Childrem-->
  15.       <id name="id" >
  16.           <generator class="native"  /><!--Autoincrement-->
  17.       </id>
  18.      <property name="nomeChildrem" />
  19.      <many-to-one  name="parent_id" column="parent_id" notnull="true" /><!--RELACIONAMENTO EM CHIDREM-->
  20.   </class>
  21. </hibernate-mapping>


Mas a Sacada nao esta ai, e sim em como vai declarar o Set, veja abaixo a classe.


  1. Parent p = new Parent();
  2. Childrem c = new Childrem();
  3. Childrem b = new Childrem();
  4. p.setChildren(new HashSet<Childrem>());//Aqui esta new HashSet, depois so add.
  5. p.getChildren().add(b);
  6. p.getChildren().add(c);
  7. session.save(p);
  8. session.flush();