@Immutable no Hibernate

@Immutable no Hibernate

1. Visão geral

Neste artigo, vamos falar sobre como podemos fazer uma entidade, coleção ou atributoImmutable no Hibernate.

Por padrão, os campos são mutáveis, o que significa que podemos realizar operações que alteram seu estado.

2. Maven

Para colocar nosso projeto em funcionamento, primeiro precisamos adicionar as dependências necessárias em nossopom.xml. E como estamos trabalhando com o Hibernate, vamos adicionar odependency correspondente:


    org.hibernate
    hibernate-core
    5.2.8.Final

E, como estamos trabalhando comHSQLDB, também precisamos:


    org.hsqldb
    hsqldb
    2.3.4

3. Anotação em Entidades

Primeiro, vamos definir uma classe de entidade simples:

@Entity
@Immutable
@Table(name = "events_generated")
public class EventGeneratedId {

    @Id
    @Column(name = "event_generated_id")
    @GeneratedValue(generator = "increment")
    @GenericGenerator(name = "increment", strategy = "increment")
    private Long id;

    @Column(name = "name")
    private String name;
    @Column(name = "description")
    private String description;

    // standard setters and getters
}

Como você notou, já adicionamos a anotação@Immutable à nossa entidade, então, se tentarmos salvar umEvent:

@Test
public void addEvent() {
    Event event = new Event();
    event.setId(2L);
    event.setTitle("Public Event");
    session.save(event);
    session.getTransaction().commit();
    session.close();
}

Então devemos obter a saída:

Hibernate: insert into events (title, event_id) values (?, ?)

A saída deve ser a mesma, mesmo se removermos a anotação, o que significa que não há efeito quando tentamos adicionar uma entidade independentemente da anotação.

Também é importante observar que em nossa entidadeEventGeneratedId, adicionamos a anotaçãoGeneratedValue, mas isso só fará diferença quando estivermos criando uma entidade. Isso é porque ele especifica a estratégia de geração para o id - quaisquer outras operações não afetarão o campoId devido à anotaçãoImmutable.

3.1. Atualizando a Entidade

Agora, não tivemos nenhum problema ao salvar uma entidade, vamos tentar atualizá-la:

@Test
public void updateEvent() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='My Event'").list().get(0);
    event.setTitle("Public Event");
    session.saveOrUpdate(event);
    session.getTransaction().commit();
}

O Hibernate irá simplesmente ignorar a operaçãoupdate sem lançar uma exceção. No entanto, se removermos a anotação@Immutable, obteremos um resultado diferente:

Hibernate: select ... from events where title='My Event'
Hibernate: update events set title=? where event_id=?

O que isso nos diz é que nosso objeto agora é mutável (mutable é o valor padrão se não incluirmos a anotação) e permitirá que a atualização faça seu trabalho.

3.2. Exclusão de uma entidade

Quando se trata de excluir uma entidade:

@Test
public void deleteEvent() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='My Event'").list().get(0);
    session.delete(event);
    session.getTransaction().commit();
}

Poderemos realizar a exclusão independentemente de ser mutável ou não:

Hibernate: select ... from events where title='My Event'
Hibernate: delete from events where event_id=?

4. Anotação em coleções

Até agora, vimos o que a anotação faz às entidades, mas como mencionamos no início, ela também pode ser aplicada a coleções.

Primeiro, vamos adicionar uma coleção à nossa classeEvent:

@Immutable
public Set getGuestList() {
    return guestList;
}

Da mesma forma que antes, adicionamos a anotação de antemão, portanto, se prosseguirmos e tentarmos adicionar um elemento à nossa coleção:

org.hibernate.HibernateException:
  changed an immutable collection instance: [com.example.entities.Event.guestList#1]

Desta vez, obtemos uma exceção, porque com coleções não podemos adicionar nem excluí-las.

4.1. Excluindo coleções

O outro cenário em queCollection por ser imutável lançará uma exceção sempre que tentarmos excluir e definirmos a anotação@Cascade.

Portanto, sempre que@Immutable estiver presente e tentarmos excluir:

@Test
public void deleteCascade() {
    Event event = (Event) session.createQuery(
      "FROM Event WHERE title='Public Event'").list().get(0);
    String guest = event.getGuestList().iterator().next();
    event.getGuestList().remove(guest);
    session.saveOrUpdate(event);
    session.getTransaction().commit();
}

Resultado:

org.hibernate.HibernateException:
  changed an immutable collection instance:
  [com.example.entities.Event.guestList#1]

5. Notas XML

Finalmente, a configuração também pode ser feita usando XML por meio do atributomutable=false:


    
        
            
        
        
    

No entanto, como basicamente implementamos os exemplos usando o método de anotação, não entraremos em detalhes usando XML.

6. Conclusão

Neste artigo rápido, exploramos a útil anotação@Immutable do Hibernate, e como isso pode nos ajudar a definir melhor semântica e restrições em nossos dados.

Como sempre, a implementação de todos esses exemplos e snippets pode ser encontrada emthe GitHub project. Este é um projeto baseado em Maven, portanto deve ser fácil importar e executar.