Como reutilizar um objeto Criteria com hibernate?
-
21-08-2019 - |
Pergunta
Eu estou tentando fazer consulta paginação resultado com hibernate e displaytag e objetos DetachedCriteria
Hibernate está fazendo o seu melhor para ficar no caminho. Deixe-me explicar ...
A maneira mais fácil de fazer a paginação com displaytag parece estar implementando a interface PaginatedList
que tem, entre outros, os seguintes métodos:
/* Gets the total number of results. */
int getFullListSize();
/* Gets the current page of results. */
List getList();
/* Gets the page size. */
int getObjectsPerPage();
/* Gets the current page number. */
int getPageNumber();
/* Get the sorting column and direction */
String getSortCriterion();
SortOrderEnum getSortDirection();
Estou pensando em jogar minha implementação PaginatedList um critério objeto e deixá-lo trabalhar junto theese linhas ...
getFullListSize() {
criteria.setProjection(Projections.rowCount());
return ((Long) criteria.uniqueResult()).intValue();
}
getList() {
if (getSortDirection() == SortOrderEnum.ASCENDING) {
criteria.addOrder(Order.asc(getSortCriterion());
} else if (getSortDirection() == SortOrderEnum.DECENDING) {
criteria.addOrder(Order.desc(getSortCriterion());
}
return criteria.list((getPageNumber() - 1) * getObjectsPerPage(),
getObjectsPerPage());
}
Mas isso não funciona, porque o addOrder()
ou as chamadas setProjection()
modificar os critérios de objeto tornando-in-utilizável para as chamadas sucessivas. Eu não sou inteiramente certo da ordem das chamadas, mas a db gera um erro em getFullListSize()
tentando fazer um "select count(*) ... order by ...
", que é obviamente errado.
Eu acho que eu poderia corrigir isso criando um objeto de meu próprio para manter o controle de condições de consulta e reconstruir o objeto Criteria para cada chamada, mas que se sente como reinventar uma outra roda. Existe uma maneira mais inteligente, possivelmente copiando os critérios inicialmente aprovadas e que trabalham nessa cópia?
Atualização :
Parece que getList
é chamado pela primeira vez, e getFullListSize
é chamado várias vezes depois, então, assim que há uma ordenação passada, getFullListSize
falhará. Não faria sentido para bater o db apenas uma vez (em getList
eu diria) e cache os resultados, sem a necessidade de copiar / redefinir o objeto Criteria
, mas ainda assim ...
Update (de novo) :
Esqueça isso, depois de já ter feito o count
eu não posso fazer o select
, e vice-versa. Eu realmente preciso de dois objetos Criteria
distinto.
Solução
Bem, DetachedCriteria são Serializable, então você tem built-in (se deselegante) apoio clone profundo. Você pode serializar os critérios iniciais para um byte [] uma vez em construção, em seguida, desserializar-lo cada vez que você quiser usá-lo.
Outras dicas
Criteria.setProjection(null);
Criteria.setResultTransformer(Criteria.ROOT_ENTITY);
Será que efetivamente "reset" os critérios entre a projeção rowCount e execução da própria critérios.
Gostaria de ter certeza seu pedido não foi adicionado antes de fazer o rowCount, vai retardar as coisas. Minha implementação de PaginatedList SEMPRE executa uma consulta de contagem antes de olhar para os resultados, por isso ordenação não é um problema.
Neste post eu avistou um método CriteriaTransformer.clone.
Isso deve copiar o objeto critérios.
Você também pode definir a projeção do seu método GetList.
Woops Eu não percebi que você estava referindo-se a java hibernate. De qualquer forma, este http://forum.hibernate.org/viewtopic.php?t=939039
post do fórum deve ser capaz de responder a sua pergunta.
feio como pode ser acabei usando o truque de serialização. Eu só seriar o objeto DetachedCriteria
para um array de bytes na construção do objeto PaginatedList
e de serialize-lo quando necessário. Ouch.
Outra pena coisa a tentar:
implementar um DAO genérico como o sugerido no de hibernação local e passá-lo para o PaginatedList objecto, juntamente com um objecto de restrições. O objeto PaginatedList seria então fazer algo parecido
Criteria.forClass(myDAO.getPersistentClass())
.add(myRestrictions)
.addOrder(<someOrder>)
e
Criteria.forClass(myDAO.getPersistentClass())
.add(myRestrictions)
.setProjection(Projections.rowCount());
Ainda não tentei isso ainda, mas deve funcionar.
public static DetachedCriteria Clone(this DetachedCriteria criteria)
{
var dummy = criteria.ToByteArray();
return dummy.FromByteArray<DetachedCriteria>();
}