@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.