Pergunta

Supondo que eu tenha aulas de usuário e grupo de usuário. Existe um grupo opcional 1-muitos para associação de usuários e a associação é mapeada de ambos os lados (o lado do grupo de usuários por meio de uma propriedade chamada "Membros", que é um hashset, o lado do usuário via propriedade "grupo").

Usando a API de critérios, como posso consultar todos os grupos, classificados pela contagem de membros do grupo?

(Editar) Eu deveria ter apontado quando perguntei isso que a paginação estava sendo realizada no SQL, para que a ordem também deve ser realizada no SQL, se possível.

Foi útil?

Solução

Outra opção seria usar a anotação @formula, que é basicamente o equivalente a criar uma seleção aninhada para que você possa obter suas contagens.

Em sua propriedade / membro do seu banco de dados em questão (que você deve criar), adicione a anotação ao getter como:

@Formula ("(selecione count (table_name.id) da tabela onde quer que ...)") public Long GetNewProperty {return NewProperty; }

Em seguida, alvo o membro diretamente para obter seus valores de contagem ...

Nota: Esteja ciente de que, ao especificar o SQL na anotação da fórmula, você deve especificar os nomes de campo diretamente ao fazer referência à tabela de objetos atuais (this), pois o hibernato lida com isso. Portanto, na sua cláusula WHERE, basta usar o ID ou qualquer outra coisa por si só ao fazer referência à tabela de objetos atuais que eu suspeito que seja um grupo de usuários.

Eu tinha que ter um setter para minha nova propriedade para que o Hibernate funcione e impedir que o compilador reclame.

Pode haver outras maneiras inteligentes de usar @formula, mas eu sou muito novo nisso e não parece haver muito documentação sobre o assunto ...

Se você nunca usou selecionamentos aninhados antes, pode ser uma ideia para você recriar o SQL primeiro - isso me ajudou.

Espero que isto ajude

Outras dicas

Não é possível por padrão usando a API CITERIA, mas você pode estender a classe org.hibernate.critriot.orde. Este artigo é sobre como estender essa classe: http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-usening-hibernate-critria-api

Minha Solution é:

public class SizeOrder extends Order {

    protected String propertyName;
    protected boolean ascending;

    protected SizeOrder(String propertyName, boolean ascending) {
        super(propertyName, ascending);
        this.propertyName = propertyName;
        this.ascending = ascending;
    }

    public String toSqlString(Criteria criteria, CriteriaQuery criteriaQuery) throws HibernateException {
        String role = criteriaQuery.getEntityName(criteria, propertyName) + '.' + criteriaQuery.getPropertyName(propertyName);
        QueryableCollection cp = (QueryableCollection) criteriaQuery.getFactory().getCollectionPersister(role);

        String[] fk = cp.getKeyColumnNames();
        String[] pk = ((Loadable) cp.getOwnerEntityPersister())
                .getIdentifierColumnNames();
        return " (select count(*) from " + cp.getTableName() + " where "
                + new ConditionFragment()
                        .setTableAlias(
                                criteriaQuery.getSQLAlias(criteria, propertyName)
                        ).setCondition(pk, fk)
                    .toFragmentString() + ") "
                + (ascending ? "asc" : "desc");
    }

    public static SizeOrder asc(String propertyName) {
        return new SizeOrder(propertyName, true);
    }
    public static SizeOrder desc(String propertyName) {
        return new SizeOrder(propertyName, false);
    }
}

O método TOSQLSTRING é baseado na classe org.hibernate.crition.sizexpression. (Fonte: http://javasourcecode.org/html/open-source/hibernate/hibernate-3.6.0.final/org/hibernate/criterion/sizexpression.java.html)

Exemplo de uso:

hibernateSession.createCriteria(UserGroup.class).addOrder( SizeOrder.asc("members") ).list();

Isso listará grupos de usuários solicitados pelo tamanho dos membros ascendentes, onde "membros" é a coleção de usuários na entidade do grupo de usuários.

Você provavelmente poderia definir uma "propriedade derivada" em sua entidade, que seria uma propriedade somente leitura que retorna o tamanho da coleção dentro dessa entidade. A maneira mais fácil de definir uma propriedade derivada é documentado aqui:

Atualizar, Inserir (Opcional - Padrões para True): Especifica que as colunas mapeadas devem ser incluídas nas instruções SQL Atualize e/ou Inserir. A definição de ambos como falsa permite uma propriedade "derivada" pura cujo valor é inicializado de outra propriedade que mapeia para a mesma coluna (s) ou por um gatilho ou outro aplicativo.

Depois que a propriedade for definida, você poderá usar o nome da propriedade como uma cláusula de ordem na API de critérios, como qualquer outra propriedade. Eu não tentei isso sozinho, no entanto.

Se funcionar, provavelmente será feito como um tipo de memória, pois não será capaz de mapeá-lo para o SQL. Se isso for um problema, o mesmo link acima documenta como implementar uma propriedade derivada usando um fragmento SQL personalizado:

Uma característica poderosa são propriedades derivadas. Essas propriedades são, por definição, somente leitura. O valor da propriedade é calculado no tempo de carregamento. Você declara o cálculo como uma expressão SQL. Isso então se traduz em uma subconeração de cláusula selecionada na consulta SQL que carrega uma instância:

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top