Hibernate los criterios del API - cómo hacer un pedido por el tamaño de la colección?

StackOverflow https://stackoverflow.com/questions/1254306

  •  12-09-2019
  •  | 
  •  

Pregunta

Suponiendo que tengo clases de usuario y UserGroup. Hay una opcional 1-muchos grupo a la asociación de usuario y la asociación se asigna desde ambos lados (el lado UserGroup a través de una propiedad llamada "miembros", que es un HashSet, el lado del usuario a través de la propiedad "grupo").

El uso de la API Criteria, ¿cómo puedo consultar I para todos los grupos, ordenados en número, de los miembros del grupo?

(Editar) Debería haber señalado cuando pregunté esto que la paginación se llevaba a cabo en el SQL, por lo que el pedido se debe también realizar en el SQL, si es posible.

¿Fue útil?

Solución

Otra opción sería utilizar la anotación @Formula que es básicamente el equivalente a la creación de un anidado de selección para que pueda obtener en sus recuentos.

En su base de datos los objetos miembro de la propiedad / en cuestión (que se debe crear), añadir la anotación al comprador como:

@Formula ( "(SELECT COUNT (TABLE_NAME.ID) de la tabla donde sea ...)") getNewProperty pública de largo {    volver newProperty; }

A continuación, dirigirse directamente al miembro de hacerse con sus valores de cuenta ...

Nota: Tenga en cuenta que al especificar el SQL dentro de la fórmula de anotación, debe especificar los nombres de los campos directamente al hacer referencia a la tabla de objetos actual (este), como ofertas de hibernación con esta misma. Así que en su cláusula WHERE sólo tiene que utilizar ID o lo que sea por su propia cuenta al hacer referencia a la tabla de objetos actuales que sospecho es UserGroup.

Yo tenía que tener un colocador para mi nueva propiedad con el fin de hibernación al trabajo y evitar el compilador de las protestas.

Puede haber otras maneras inteligentes de utilizar @Formula, pero soy bastante nuevo en esto y no parece estar muy documentación sobre el tema ...

Si usted nunca ha usado antes de Selects anidada, que podría ser una buena idea para que usted acaba de volver a crear en SQL primero -. Que me ayudó

Espero que esto ayude

Otros consejos

No es posible por defecto utilizando la API citeria pero se puede extender la clase org.hibernate.criterion.Order. Este artículo es acerca de cómo extender la clase: http://blog.tremend.ro/2008/06/10/how-to-order-by-a-custom-sql-formulaexpression-when-using-hibernate -Criterios-api

Mi sollution es:

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);
    }
}

El método se basa en toSqlString clase org.hibernate.criterion.SizeExpression. (Fuente: http://javasourcecode.org/html/open-source/hibernate/hibernate-3.6.0.Final/org/hibernate/criterion/SizeExpression.java.html )

Ejemplo de uso:

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

grupos de usuarios Esta lista ordenados por el tamaño de los miembros ascendente, donde "miembros" es la colección del usuario en la entidad UserGroup.

Probablemente se podría por lo que esta definiendo una "propiedad derivada" en su entidad, lo que sería una propiedad de sólo lectura que devuelve el tamaño de la colección dentro de esa entidad. La forma más sencilla de definir una propiedad derivada es documentado aquí :

  

update, insert (opcional - por defecto   true): Especifica que el mapeado   columnas deben ser incluidos en SQL   UPDATE y / o INSERT declaraciones.   Ajuste de los dos en false permite una pura   "Derivada" propiedad cuyo valor es   inicializado desde alguna otra propiedad   que se asigna a la misma columna (s), o por   un disparador o en otra aplicación.

Una vez que se define la propiedad, usted debe ser capaz de utilizar el nombre de la propiedad como una cláusula de orden en la API de criterios, al igual que cualquier otra propiedad. No he probado esto por mí mismo, sin embargo.

Si funciona, es probable que va a ser hecho como una ordenación en memoria, ya que no será capaz de asignar a SQL. Si esto es un problema, entonces el mismo enlace anterior documentos cómo implementar una propiedad derivada utilizando un fragmento de SQL personalizada:

  

Una característica de gran alcance se deriva   propiedades. Estas propiedades son por   definición de sólo lectura. La propiedad   valor se calcula en tiempo de carga. Tú   declarar la computación como un SQL   expresión. Esto luego se traduce a una   SELECT subconsulta cláusula en el SQL   consulta que carga un ejemplo:

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top