JPA: Ordernando listas e utilizando Map como atributo mapeado

Olá pessoal, tudo bem?

Como ordenar uma lista em um relacionamento sem utilizar uma query? Ou então como mapear seu relacionamento dentro de um Map? Vamos ver como são simples essas funções.

Vou utilizar códigos antigos dos outros posts. Para montar um ambiente para executar o código de hoje, você poderá olhar os posts antigos: @ManyToMany Unidirecional e Bidirecional, JPA @OneToMany e @ManyToOne Unidirecional e Bidirecional, @OneToOne Unidirecional e Bidirecional, Mapeando Duas Tabelas em uma Classe, Mapeando Datas (Date) e Enum, Chave Primária Composta, SequenceGenerator, TableGenerator – Chave Primária Simples, Auto Create Schema Script com: Ant, Hibernate 3 e JPA 2, Tutorial Hibernate 3 com JPA 2.

Vou postar aqui o código da classe Customer, Dog, e Main:

package com;

//Using the * to make the import list smaller
import javax.persistence.*;

@Entity
@Table(name="DOG")
@SequenceGenerator(name="DOG_SEQUENCE", sequenceName="DOG_SEQUENCE", allocationSize=1, initialValue=0)
public class Dog {

    public Dog(){

    }

    public Dog(String name){
        this.name = name;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator="DOG_SEQUENCE")
    private int id;

    @Column
    private String name;

    // Getters and Setters
}
package com;

import java.util.List;

//Using the * to make the import list smaller
import javax.persistence.*;

@Entity
@Table(name = "CUSTOMER")
@SequenceGenerator(name = "CUSTOMER_SEQUENCE", sequenceName = "CUSTOMER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_SEQUENCE")
    private int id;

    @Column
    private String name;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @JoinTable(name="CUSTOMER_HAS_DOGS", joinColumns={@JoinColumn(name="CUSTOMER_ID", referencedColumnName="id")}, inverseJoinColumns={@JoinColumn(name="DOG_ID", referencedColumnName="id")})
    private List dogs;

    // Getters and Setters
}
package com;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("Hello");
        EntityManager em = emf.createEntityManager();

        try {
            em.getTransaction().begin();

            List dogs = new ArrayList();
            dogs.add(new Dog("Terminator"));
            dogs.add(new Dog("Fluffy"));
            dogs.add(new Dog("Bacon"));

            Customer customer = new Customer();
            customer.setName("Arnold");
            customer.setDogs(dogs);

            em.persist(customer);

            em.getTransaction().commit();
        }
        catch (Exception e) {
            em.getTransaction().rollback();
            e.printStackTrace();
        }
        finally{
            emf.close();
        }

        System.out.println("It is over");
    }
}

Ao executar o código acima você irá criar dados necessário para poder começar o estudo de hoje.

Após uma pequena alteração na classe Main, vamos exibir os itens da lista Dog de um Customer. Veja a baixo o novo código da classe Main e o resultado impressao:

package com;

//Using the * to make the import list smaller
import javax.persistence.*;

public class Main {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("Hello");
        EntityManager em = emf.createEntityManager();

        try {
            em.getTransaction().begin();

            Customer customer = em.find(Customer.class, 1);

            for(Dog dog : customer.getDogs()){
                System.out.println(dog.getName());
            }

            em.getTransaction().commit();
        }
        catch (Exception e) {
            em.getTransaction().rollback();
            e.printStackTrace();
        }
        finally{
            emf.close();
        }

        System.out.println("It is over");
    }
}
Unordered List

Note que os objetos da lista não estão sendo impressos em ordem alfabética do nome do cachorro. Mas, caso queiramos ordenar os resultados como faríamos?

Iremos utilizar a anotação @OrderBy que nos permite especificar o nome do campo da tabela ao qual queremos que nossa lista seja ordenada.

Basta adicionar a anotação em nossa classe Customer, e nossa lista será ordenada. Veja como ficará:

package com;

import java.util.List;

//Using the * to make the import list smaller
import javax.persistence.*;

@Entity
@Table(name = "CUSTOMER")
@SequenceGenerator(name = "CUSTOMER_SEQUENCE", sequenceName = "CUSTOMER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_SEQUENCE")
    private int id;

    @Column
    private String name;

    @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
    @OrderBy("name")
    @JoinTable(name="CUSTOMER_HAS_DOGS", joinColumns={@JoinColumn(name="CUSTOMER_ID", referencedColumnName="id")}, inverseJoinColumns={@JoinColumn(name="DOG_ID", referencedColumnName="id")})
    private List dogs;

    // Getters and Setters
}

Execute nossa classe Main e a ordenação irá aparecer:

Bem simples. Lógico que é apenas uma solução para caso você queira ordenar sua coleção sem ter que ter uma nativeQuery/namedQuery/Criteria para isso.

E se precisássemos colocar nossa lista dentro de um map, como fazer?

Vamos criar um atributo com o java.util.Map e a anotação @MapKey:

package com;

import java.util.List;
import java.util.Map;

//Using the * to make the import list smaller
import javax.persistence.*;

@Entity
@Table(name = "CUSTOMER")
@SequenceGenerator(name = "CUSTOMER_SEQUENCE", sequenceName = "CUSTOMER_SEQUENCE", allocationSize = 1, initialValue = 0)
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "CUSTOMER_SEQUENCE")
    private int id;

    @Column
    private String name;

    @OneToOne(cascade = CascadeType.ALL, optional = true, fetch = FetchType.EAGER, orphanRemoval = true)
    @JoinColumn(name = "USER_ID", nullable = true)
    private User user;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @OrderBy("name")
    @JoinColumn(name = "CUSTOMER_ID")
    private List dogs;

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name = "CUSTOMER_ID")
    @MapKey(name = "id")
    private Map dogsInMap;

    // Getters and Setters
}

O campo “id” é o campo que será utilizado para chave do mapa.

E para finalizar executemos a classe Main para exibir a iteração sobre nosso map:

package com;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class Main {

    public static void main(String[] args) {
        EntityManagerFactory emf = Persistence.createEntityManagerFactory("Hello");
        EntityManager em = emf.createEntityManager();

        try {
            em.getTransaction().begin();

            Customer customer = em.find(Customer.class, 1);

            System.out.println("Ordered List");
            for(Dog dog : customer.getDogs()){
                System.out.println(dog.getName());
            }

            System.out.println("nThe map: ");
            for(int id : customer.getDogsInMap().keySet()){
                Dog dog = customer.getDogsInMap().get(id);
                System.out.println(dog.getName());
            }

            em.getTransaction().commit();
        }
        catch (Exception e) {
            em.getTransaction().rollback();
            e.printStackTrace();
        }
        finally{
            emf.close();
        }

        System.out.println("It is over");
    }
}

Fiz a iteração dentro do Map buscado pela chave (key) para mostrar que o atributo da chave foi corretamente populado.

Espero que esse post possa te ajudar.

Até a próxima.
o_

Leave a Comment