Visão geral
Neste guia, você pode aprender a usar a extensão MongoDB para Hibernate ORM para executar operações de criação, leitura, atualização e exclusão (CRUD) em suas coleções do MongoDB.
Dados de amostra
Os exemplos neste guia usam a entidade Movie, que representa a coleção sample_mflix.movies dos conjuntos de dados de amostra do Atlas. A entidade Movie tem a seguinte definição:
import com.mongodb.hibernate.annotations.ObjectIdGenerator;import org.bson.types.ObjectId;import java.time.Instant;import java.util.List;import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;import jakarta.persistence.FetchType;import jakarta.persistence.Id;import jakarta.persistence.OneToMany;import jakarta.persistence.Table;
@Entity@Table(name = "movies")public class Movie { @Id @ObjectIdGenerator private ObjectId id; private String title; private String plot; private int year; private List<String> cast; private List<String> directors; private Instant released; @Embedded private Awards awards; @OneToMany(mappedBy = "movie", fetch = FetchType.LAZY) private List<Comment> comments;
public Movie(String title, String plot, int year, List<String> cast, List<String> directors, Instant released, Awards awards) { this.title = title; this.plot = plot; this.year = year; this.cast = cast; this.directors = directors; this.released = released; this.awards = awards; }
public Movie() {
}
public ObjectId getId() { return id; }
public String getTitle() { return title; }
public void setTitle(String title) { this.title = title; }
public String getPlot() { return plot; }
public void setPlot(String plot) { this.plot = plot; }
public int getYear() { return year; }
public void setYear(int year) { this.year = year; }
public List<String> getCast() { return cast; }
public void setCast(List<String> cast) { this.cast = cast; }
public List<String> getDirectors() { return directors; }
public void setDirectors(List<String> directors) { this.directors = directors; }
public Awards getAwards() { return awards; }
public void setAwards(Awards awards) { this.awards = awards; }
public Instant getReleased() { return released; }
public void setReleased(Instant released) { this.released = released; }
public List<Comment> getComments() { return comments; }
public void setComments(List<Comment> comments) { this.comments = comments; }}Para aprender como criar um aplicativo Java que use a Extensão MongoDB para Hibernate ORM para interagir com essa coleção de amostras do MongoDB, veja o tutorial Get Started.
Importante
Contextos de persistência
Para habilitar o ORM do Hibernate para interagir com o banco de dados, você deve executar operações dentro de um contexto de persistência utilizando um Hibernate Session ou um Jakarta Persistence EntityManager. Você também deve executar operações de gravação dentro de uma transação para modificar os dados do MongoDB e manter a integridade dos dados.
Antes de executar os exemplos neste guia, adicione o contexto de persistência e o código de gerenciamento de transações ao seu aplicativo que se assemelha ao código a seguir:
var sf = HibernateUtil.getSessionFactory();Session session = sf.openSession();Transaction tx = session.beginTransaction();
// ... Perform CRUD operations here
tx.commit();session.close();sf.close();Para utilizar uma sessão, você deve criar um arquivo HibernateUtil.java que configure um SessionFactory. Para saber mais, veja a etapa Configurar seu aplicativo do tutorial de Introdução.
// Replace <persistence unit> with the name of your persistence unit in the persistence.xml file EntityManagerFactory emf = Persistence.createEntityManagerFactory("<persistence unit>"); EntityManager entityManager = entityManagerFactory.createEntityManager(); entityManager.getTransaction().begin();
// ... Perform CRUD operations here
entityManager.getTransaction().commit();entityManager.close();emf.close;Para utilizar um EntityManager, você deve criar um arquivo persistence.xml que declara uma unidade de persistência. Para aprender mais, veja o Tutorial usando APIs padrão JPA na documentação do ORM do Hibernate.
Insira documentos
Crie um documento passando uma instância de entidade para os seguintes métodos, que inserem o documento correspondente em sua coleção:
org.hibernate.Session.persist(): Use a API do Hibernar para aplicar suas alterações no banco de dadosjakarta.persistence.EntityManager.persist(): Use a API de Persistência de Jakarta para aplicar suas alterações no banco de dados
Dica
Para aprender mais sobre como criar instâncias de entidade e persisti-las em seu banco de dados, consulte Making entities persistent no guia do usuário do Hibernate ORM.
Exemplo
O exemplo seguinte cria uma nova instância de entidade Movie e utiliza o método persist() para inserir um documento correspondente na coleção sample_mflix.movies:
var myMovie = new Movie();myMovie.setTitle("Knives Out");myMovie.setYear(2019);myMovie.setCast(List.of("Ana de Armas", "Daniel Craig", "Chris Evans"));myMovie.setPlot("Detective Benoit Blanc investigates the mysterious death of crime novelist Harlan Thrombey, " + "unraveling lies as every Thrombey family member becomes a suspect.");session.persist(myMovie);var myMovie = new Movie();myMovie.setTitle("Knives Out");myMovie.setYear(2019);myMovie.setCast(List.of("Ana de Armas", "Daniel Craig", "Chris Evans"));myMovie.setPlot("Detective Benoit Blanc investigates the mysterious death of crime novelist Harlan Thrombey, " + "unraveling lies as every Thrombey family member becomes a suspect.");entityManager.persist(myMovie);Ler documentos
Para recuperar documentos da sua coleção, passe seus critérios de query para o método createQuery(). As seguintes APIs fornecem o método createQuery():
API
Sessiondo Hibernate: use a sintaxe da linguagem de query do Hibernate (HQL) para definir suas queriesAPI
EntityManagerdo Jakarta Persistence: Use a sintaxe da linguagem de query JPQL (Jakarta Persistence Query Language), um subconjunto do HQL, para definir suas queries
Dica
Para saber mais sobre como recuperar dados usando a sintaxe HQL e JPQL, consulte declarações selecionadas no guia de query ORM do Hibernate.
Observação
Esta seção descreve como ler documentos usando HQL e JPQL, mas você também pode usar o construtor de critérios ou querys nativas para recuperar dados. Para saber mais, consulte os seguintes guias:
Exemplo de devolução de um documento
Para recuperar apenas um documento que corresponda aos seus critérios de query, encadeie o método getSingleResult() ao método createQuery(). O exemplo a seguir recupera um documento com um valor title de "Boyhood" da coleção sample_mflix.movies:
var singleResult = session.createQuery("from Movie where title = :t", Movie.class) .setParameter("t", "Boyhood") .getSingleResult();System.out.println("Title: " + singleResult.getTitle() + ", Year: " + singleResult.getYear());var singleResult = entityManager.createQuery("select m from Movie m where m.title = :t", Movie.class) .setParameter("t", "Boyhood") .getSingleResult();System.out.println("Title: " + singleResult.getTitle() + ", Year: " + singleResult.getYear());Dica
Sintaxe de consulta
Para saber mais sobre a sintaxe HQL e JPQL, consulte Um Guia da linguagem de query do Hibernate na documentação do ORM do Hibernate.
Exemplo de devolução de vários documentos
O exemplo seguinte chama o método createQuery() em uma sessão para recuperar documentos da coleção sample_mflix.movies. O código usa HQL e JPQL para retornar documentos que tenham um valor year de 1920 e imprime seus valores title:
var results = session.createQuery("from Movie where year = :y", Movie.class) .setParameter("y", 1920) .getResultList();results.forEach(movie -> System.out.println(movie.getTitle()));var results = entityManager.createQuery("select m from Movie m where m.year = :y", Movie.class) .setParameter("y", 1920) .getResultList();results.forEach(movie -> System.out.println(movie.getTitle()));Modificar documentos
Você pode executar as seguintes operações para modificar documentos em uma coleção:
Atualizar um documento: Chame os métodos de configuração da sua entidade para alterar os valores de campo de uma instância de entidade e, em seguida, use uma sessão ou gerente de entidade para persistir suas alterações.
Atualizar vários documentos: Passe uma declaração de atualização para os métodos
createQuery()oucreateMutationQuery()em uma sessão ou gerente de entidades. Em seguida, chame o métodoexecuteUpdate()para aplicar suas alterações no banco de dados.
Dica
Para aprender mais sobre como modificar dados usando o Hibernate ORM, consulte os seguintes recursos:
Modificando o estado gerenciado/persistente no guia do usuário do Hibernate ORM
Atualizar declarações no guia de query do Hibernar ORM
Atualizar um exemplo
O exemplo a seguir recupera um documento por seu valor ObjectId. Em seguida, o exemplo chama o método setTitle() da entidade Movie para atualizar o valor de title do documento para "Jurassic Park I":
// Your ObjectId value might differMovie movieById = session.get(Movie.class, new ObjectId("573a1399f29313caabcedc5d"));movieById.setTitle("Jurassic Park I");session.persist(movieById);// Your ObjectId value might differMovie movieById = entityManager.find(Movie.class, new ObjectId("573a1399f29313caabcedc5d"));movieById.setTitle("Jurassic Park I");entityManager.persist(movieById);Atualizar vários exemplos
O exemplo a seguir atualiza o valor title dos documentos correspondentes de "The Three Stooges" para "The 3 Stooges". Em seguida, o exemplo chama o método executeUpdate() para aplicar as alterações no banco de dados:
var updateResult = session.createMutationQuery( "update Movie set title = :new where title = :old") .setParameter("new", "The 3 Stooges") .setParameter("old", "The Three Stooges") .executeUpdate();System.out.println("Number of movies updated: " + updateResult);var updateResult = entityManager.createQuery( "update Movie m set m.title = :new where m.title = :old") .setParameter("new", "The 3 Stooges") .setParameter("old", "The Three Stooges") .executeUpdate();System.out.println("Number of movies updated: " + updateResult);A cláusula SET de uma declaração de atualização em massa também pode usar uma expressão em vez de um valor literal. A expressão pode referenciar o campo que está sendo atualizado ou outro campo na entidade.
O exemplo a seguir usa uma expressão aritmética para incrementar o valor de year de documentos que têm um valor de title de "The 3 Stooges":
var updateResult = session.createMutationQuery( "update Movie m set m.year = m.year + 1 where m.title = :title") .setParameter("title", "The 3 Stooges") .executeUpdate();System.out.println("Number of movies updated: " + updateResult);O exemplo a seguir usa uma referência de campo para definir o valor de plot para corresponder ao valor de title para documentos que têm um valor de year de 1920:
var updateResult = session.createMutationQuery( "update Movie m set m.plot = m.title where m.year = :year") .setParameter("year", 1920) .executeUpdate();System.out.println("Number of movies updated: " + updateResult);Exemplo de atualizar vários documentos com base em lógica condicional
O exemplo a seguir usa uma expressão CASE para definir o valor plot dependendo se o valor year de cada documento é posterior ao ano 2000. A extensão Hibernate ORM traduz a expressão CASE para o operador $switch do MongoDB e aplica a atualização usando um estágio de pipeline $set:
var updateResult = session.createMutationQuery( "update Movie m set m.plot = case when m.year > 2000 then 'Modern release' " + "else 'Classic release' end where m.title = :title") .setParameter("title", "The 3 Stooges") .executeUpdate();System.out.println("Number of movies updated: " + updateResult);Para aprender mais sobre expressões CASE, consulte a seção Expressões de caso de uso para lógica condicional no guia Especificar uma query.
Documentos do Upsert
Uma operação upsert atualiza um documento se um documento correspondente existir, ou insere um novo documento se não houver correspondência. Para realizar um upsert, use o método upsert() ou upsertMultiple(). Esses métodos estão disponíveis apenas na API StatelessSession do Hibernate.
Observação
Uma instância StatelessSession não acompanha as alterações nas entidades que recupera. Para salvar as alterações em uma entidade, passe-a para outro método de gravar. Use StatelessSession para fluxos de trabalho de gravar em massa.
Requisitos da entidade
A extensão Hibernate ORM cria o filtro para uma operação de upsert a partir do identificador da sua entidade, portanto, seu aplicativo deve atribuir o valor do identificador antes de chamar upsert().
O método upsert() não gera valores de identificador, mesmo que sua entidade use a anotação @ObjectIdGenerator. Se você não atribuir um valor de identificador, a extensão Hibernate ORM armazenar o documento com um valor null _id.
Você pode usar a anotação @Column(updatable = false) para proteger um campo de atualizações durante uma operação de upsert. A seguinte definição de entidade Movie anota o campo released com @Column(updatable = false), o que instrui a extensão Hibernate ORM a gravar no campo quando ele insere um documento, mas a omitir o campo quando ele atualiza um documento existente:
@Entity@Table(name = "movies")public class Movie { @Id @ObjectIdGenerator private ObjectId id;
private String title; private int year;
@Column(updatable = false) private Instant released;
// Getters and setters omitted}A extensão Hibernate ORM envia campos que são inseríveis e atualizáveis no operador $set da declaração de atualizar gerada. Ele envia campos somente inseríveis, como campos anotados com @Column(updatable = false), no operador $setOnInsert.
Exemplo de Upsert One
O exemplo a seguir cria uma instância de entidade Movie e a passa para o método upsert() . Se um documento que tem o valor ObjectId especificado existir, a extensão Hibernate ORM atualizará os valores title e year desse documento. Caso contrário, a extensão Hibernate ORM insere um novo documento:
try (StatelessSession statelessSession = sf.openStatelessSession()) { var movie = new Movie(); movie.setId(new ObjectId("573a1398f29313caabce9682")); movie.setTitle("The General"); movie.setYear(1926); movie.setReleased(Instant.parse("1927-02-24T00:00:00Z"));
statelessSession.upsert(movie);}Exemplo de upsert múltiplo
Para realizar um upsert de várias instâncias de entidade em uma única operação, passe uma lista de instâncias para o método upsertMultiple(). O exemplo a seguir faz upsert de duas instâncias de entidade Movie:
try (StatelessSession statelessSession = sf.openStatelessSession()) { var firstMovie = new Movie(); firstMovie.setId(new ObjectId("573a1398f29313caabce9682")); firstMovie.setTitle("The General"); firstMovie.setYear(1926);
var secondMovie = new Movie(); secondMovie.setId(new ObjectId("573a1398f29313caabce9683")); secondMovie.setTitle("Metropolis"); secondMovie.setYear(1927);
statelessSession.upsertMultiple(List.of(firstMovie, secondMovie));}Limitações do upsert
Os seguintes mapeamentos de entidade não são compatíveis em operações de upsert. Quando você upsert uma entidade que usa um desses mapeamentos, a extensão Hibernate ORM lança um FeatureNotSupportedException:
Entidades que possuem um campo anotado com
@Version.Entidades que possuem um campo anotado com
@Column(insertable = false). A linguagem de query do MongoDB não oferece nenhuma maneira de gravar um campo apenas quando uma operação corresponde a um documento existente.Entidades cujo único atributo persistente é o identificador. Um upsert nesse tipo de entidade não tem campos para atualizar, portanto, a extensão Hibernate ORM rejeita a operação.
Exclua documentos
Você pode executar as seguintes operações para excluir documentos de uma coleção:
Excluir um documento: Chame o método
remove()em um gerente de sessão ou entidade, passando a instância da entidade que você deseja excluir como argumento.Excluir vários documentos: Passe uma declaração de exclusão para os métodos
createQuery()oucreateMutationQuery()em uma sessão ou gerente de entidades. Em seguida, chame o métodoexecuteUpdate()para aplicar suas alterações no banco de dados.
Dica
Para aprender mais sobre como excluir dados usando o Hibernate ORM, consulte os seguintes recursos:
Excluindo entidades no guia do usuário do Hibernar ORM
Excluir declarações no guia de query do Hibernar ORM
Excluir um exemplo
O exemplo a seguir recupera um documento por seu valor ObjectId. Em seguida, o exemplo chama o método remove() em uma sessão para excluir o documento correspondente da coleção sample_mflix.movies:
// Your ObjectId value might differMovie movieToDelete = session.get(Movie.class, new ObjectId("573a1399f29313caabcedc5d"));session.remove(movieToDelete);// Your ObjectId value might differMovie movieToDelete = entityManager.find(Movie.class, new ObjectId("573a1399f29313caabcedc5d"));entityManager.remove(movieToDelete);Excluir vários exemplos
O exemplo a seguir exclui todos os documentos que têm um valor de year de 1920 da coleção sample_mflix.movies. O exemplo passa uma declaração excluir para o método createMutationQuery() e, em seguida, chama o método executeUpdate() para aplicar as alterações no banco de dados:
var deleteResult = session.createMutationQuery( "delete Movie where year = :y") .setParameter("y", 1920) .executeUpdate();System.out.println("Number of movies deleted: " + deleteResult);var deleteResult = entityManager.createQuery( "delete Movie m where m.year = :y") .setParameter("y", 1920) .executeUpdate();System.out.println("Number of movies deleted: " + deleteResult);Informações adicionais
Para saber mais sobre como executar operações CRUD usando o ORM do Hibernate, consulte os seguintes recursos:
Contexto de persistência no guia do usuário do Hibernate ORM
Tipos de declaração no guia de query do Hibernate ORM
Para exibir mais exemplos de criar, ler, atualizar e excluir, consulte as seguintes seções do tutorial de Introdução:
Para aprender mais sobre como usar a extensão Hibernate ORM para executar queries, consulte os seguintes guias: