Consulta nomeada de hibernação
1. Visão geral
Uma grande desvantagem de ter HQL e SQL espalhados pelos objetos de acesso a dados é que isso torna o código ilegível. Portanto, pode fazer sentido agrupar todos os HQL e SQL em um único local e usar apenas sua referência no código de acesso a dados real. Felizmente, o Hibernate nos permite fazer isso com consultas nomeadas.
Uma consulta nomeada é uma consulta definida estaticamente com uma sequência de consultas imutável predefinida. Eles são validados quando a fábrica de sessão é criada, fazendo com que o aplicativo falhe rapidamente em caso de erro.
Neste artigo, veremos como definir e usar Hibernate Named Queries usando as anotações@NamedQuerye@NamedNativeQuery.
2. A entidade
Vejamos primeiro a entidade que usaremos neste artigo:
@Entity
public class DeptEmployee {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private long id;
private String employeeNumber;
private String designation;
private String name;
@ManyToOne
private Department department;
// getters and setters
}
Em nosso exemplo, recuperaremos um funcionário com base em seu número de funcionário.
3. Consulta nomeada
Para definir isso como uma consulta nomeada, usaremos a anotaçãoorg.hibernate.annotations.NamedQuery. Ele estende o javax.persistence.NamedQuery com recursos do Hibernate.
Vamos defini-lo como uma anotação da classeDeptEmployee:
@org.hibernate.annotations.NamedQuery(name = "DeptEmployee_findByEmployeeNumber",
query = "from DeptEmployee where employeeNumber = :employeeNo")
It’s important to note that every @NamedQuery annotation is attached to exactly one entity class or mapped superclass. But,since the scope of named queries is the entire persistence unit, we should select the query name carefully to avoid a collision. E conseguimos isso usando o nome da entidade como prefixo.
Se tivermos mais de uma consulta nomeada para uma entidade, usaremos a anotação@NamedQueries para agrupá-los:
@org.hibernate.annotations.NamedQueries({
@org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindByEmployeeNumber",
query = "from DeptEmployee where employeeNumber = :employeeNo"),
@org.hibernate.annotations.NamedQuery(name = "DeptEmployee_FindAllByDesgination",
query = "from DeptEmployee where designation = :designation"),
@org.hibernate.annotations.NamedQuery(name = "DeptEmployee_UpdateEmployeeDepartment",
query = "Update DeptEmployee set department = :newDepartment where employeeNumber = :employeeNo"),
...
})
Observe que a consulta HQL pode ser uma operação no estilo DML. Portanto, não precisa ser apenas uma instruçãoselect. Por exemplo, podemos ter uma consulta de atualização como emDeptEmployee_UpdateEmployeeDesignation acima.
3.1. Configurando recursos de consulta
Podemos definir vários recursos de consulta com a anotação@NamedQuery . Vejamos um exemplo:
@org.hibernate.annotations.NamedQuery(
name = "DeptEmployee_FindAllByDepartment",
query = "from DeptEmployee where department = :department",
timeout = 1,
fetchSize = 10
)
Aqui, configuramos o intervalo de tempo limite e o tamanho da busca. Além desses dois, também podemos definir recursos como:
-
cacheable - se a consulta (resultados) pode ser armazenada em cache ou não
-
cacheMode - o modo de cache usado para esta consulta; pode serGET, IGNORE, NORMAL, PUT, ouREFRESH
-
cacheRegion - se os resultados da consulta puderem ser armazenados em cache, nomeie a região do cache de consulta a ser usada
-
comment - um comentário adicionado à consulta SQL gerada; direcionado para DBAs
-
flushMode - o modo de liberação para esta consulta, um deALWAYS, AUTO, COMMIT, MANUAL, ouPERSISTENCE_CONTEXT
3.2. Usando a consulta nomeada
Agora que definimos a consulta nomeada, vamos usá-la para recuperar um funcionário:
Query query = session.createNamedQuery("DeptEmployee_FindByEmployeeNumber",
DeptEmployee.class);
query.setParameter("employeeNo", "001");
DeptEmployee result = query.getSingleResult();
Aqui, usamos o métodocreateNamedQuery. Ele pega o nome da consulta e retorna um sobjetoorg.hibernate.query.Query .
4. Consulta Nativa Nomeada
Além das consultas HQL, também podemos definir o SQL nativo como uma consulta nomeada. Para fazer isso, podemos usar a anotação@NamedNativeQuery. Embora seja semelhante ao@NamedQuery, ele requer um pouco mais de configuração.
Vamos explorar esta anotação usando um exemplo:
@org.hibernate.annotations.NamedNativeQueries(
@org.hibernate.annotations.NamedNativeQuery(name = "DeptEmployee_GetEmployeeByName",
query = "select * from deptemployee emp where name=:name",
resultClass = DeptEmployee.class)
)
Como esta é uma consulta nativa, teremos que dizer ao Hibernate para qual classe de entidade mapear os resultados. Consequentemente, usamos aresultClass property para fazer isso.
Outra forma de mapear os resultados é usar a spropertyresultSetMapping . Aqui, podemos especificar o nome de umSQLResultSetMapping predefinido.
Observe que podemos usar apenas um deresultClasseresultSetMapping.
4.1. Usando a consulta nativa nomeada
Para usar a consulta nativa nomeada, podemos usarSession.createNamedQuery():
Query query = session.createNamedQuery("DeptEmployee_FindByEmployeeName", DeptEmployee.class);
query.setParameter("name", "John Wayne");
DeptEmployee result = query.getSingleResult();
Ou oSession.getNamedNativeQuery():
NativeQuery query = session.getNamedNativeQuery("DeptEmployee_FindByEmployeeName");
query.setParameter("name", "John Wayne");
DeptEmployee result = (DeptEmployee) query.getSingleResult();
A única diferença entre essas duas abordagens é o tipo de retorno. A segunda abordagem retorna umNativeQuery, que é uma subclasse deQuery.
5. Procedimentos e funções armazenados
Podemos usar a anotação@NamedNativeQuery para definir chamadas para procedimentos armazenados e funções também:
@org.hibernate.annotations.NamedNativeQuery(
name = "DeptEmployee_UpdateEmployeeDesignation",
query = "call UPDATE_EMPLOYEE_DESIGNATION(:employeeNumber, :newDesignation)",
resultClass = DeptEmployee.class)
Observe que, embora esta seja uma consulta de atualização, usamos o spropertyresultClass . Isso ocorre porque o Hibernate não oferece suporte a consultas escalares nativas puras. E a maneira de contornar o problema é definir umresultClass ou aresultSetMapping.
6. Conclusão
Neste artigo, vimos como definir e usar consultas HQL e nativas nomeadas.
O código-fonte está disponívelover on GitHub.