2008-11-05 18 views
9

no estoy seguro de cómo describir este problema, así que creo que un ejemplo es la mejor manera de hacer mi pregunta:relación ManyToMany Consulta con los Criterios de Hibernate

Tengo dos tablas con una relación de muchos a muchos:

DriversLicencia < -> LicenceClass

LicenceClass es cosas como "Coche", "Moto" y "Medium Rigid".

Al utilizar los criterios de Hibernate, ¿cómo puedo encontrar todas las licencias que tienen licencias de "automóvil" y "moto"?

ACTUALIZACIÓN 12/11/2008 Descubrí que esto se puede lograr fácilmente mediante el uso de un Transformador de resultados personalizado. Sin embargo, el problema es que un transformador de resultados solo se aplica DESPUÉS de que la consulta arroje sus resultados, en realidad no se convierte en parte del SQL. Así que supongo que mi pregunta ahora es "¿Puedes hacer lo que inicialmente describí en SQL, y hay un análogo de Hibernate Criteria?"

Respuesta

5

Así es como finalmente lo logré utilizando HQL:

public List<DriversLicence> findDriversLicencesWith(List<LicenceClass> licenceClasses) { 
    String hqlString = "select dl from DriversLicenceImpl dl where 1=1 "; 
    for (int i = 0; i < licenceClasses.size(); i++) { 
     hqlString += " and :licenceClass" + i + " = some elements(dl.licenceClasses)"; 
    } 

    Query query = getSession().createQuery(hqlString); 
    for (int i = 0; i < licenceClasses.size(); i++) { 
     query.setParameter("licenceClass" + i, licenceClasses.get(i)); 
    } 
    return query.list(); 
} 

o el uso de criterios de Hibernate con un sqlRestriction:

for (LicenceClass licenceClass : licenceClasses) {    
    criteria.add(Restrictions.sqlRestriction("? = some(select " + LicenceClass.PRIMARY_KEY + " from " + 
        LICENCE_CLASS_JOIN_TABLE + " where {alias}." + 
        DriversLicence.PRIMARY_KEY + " = " + DriversLicence.PRIMARY_KEY + ")", 
        licenceClass.getId(), Hibernate.LONG)); 
} 

LICENCE_CLASS_JOIN_TABLE es el nombre de la tabla que Hibernate genera para apoyar la muchos- relación de muchos a controladores entre licencia y clase de licencia.

0

Aún puede usar la notación de puntos para trabajar en las relaciones. Por ejemplo, suponiendo que tiene una propiedad y la propiedad DriversLicence.licenceClass LicenceClass.type, entonces:

session.createCriteria(DriversLicence.class) 
    .add(Expression.or(
    Expression.eq("licenceClass.type", "Car"), 
    Expression.eq("licenceClass.type", "Motorbike") 
    ) 
).list(); 

Personalmente, sin embargo, me gustaría simplemente evitan el uso de criterios en este caso, porque no es una consulta dinámica, pero en lugar de utilizar:

session.createQuery("from DriversLicence where licenceClass.type in (:types)") 
    .setParameterList("types", myListOfTypes) 
    .list(); 
+0

No creo que esto vaya a funcionar. Quiero encontrar todas las licencias que tienen clases de licencia ** ** ** "Coche" y "Moto". Tampoco**. –

+0

Ahh ... buen punto. Aunque no es el más eficiente, se podría: seleccione dl de DriversLicence dl unirse a d.licenceType lt donde "coche" = algunos elementos (lt.type) y "Moto" = algunos elementos (lt.type) Este también se puede cambiar para usar criterios (¡sin caracteres!) – Nick

+0

Sí, ese es el tipo de cosa que quiero, pero ¿cómo se hace con los criterios? ¡Publica otra respuesta si quieres! –

-1

'No creo que esto vaya a funcionar. Quiero encontrar todas las licencias que tengan ambos "Coche" y "Moto" '

Expresión de usuario.y (....) en lugar de Expression.or (....) en el fragmento provisto por Nick

+1

No, eso también es incorrecto. Estoy empezando a pensar que este caso de uso aparentemente simple simplemente no es posible en Hibernate. ¿Alguien quiere confirmarlo y explicar por qué? –

0

Tuve un problema similar pero lo solucioné usando HQL, tengo una clase "Enterprise" que está relacionada con la clase "Usuario" y también relacionada con la clase "Rol", tienen una relación de muchos a muchos, cuando lo necesito todas las empresas relacionadas con un usuario específico hago lo siguiente;

Select e from Enterprise As e inner join e.Users As u inner join u.Roles As r 
Where u.UserCode=? 

Supongo que en tu caso deberías hacer algo como;

Select dl from LicenceClass As l inner join l.DriversLicences As dl 
Where 
l.LicenseClass.Name = ? OR 
l.LicenseClass.Name=? OR 
l.LicenseClass.Name=? 

Espero que ayude.

0

Otra opción es encadenar uniones (una unión por cada LicenseClass). Solía ​​criterios constructor y predicados como esto

List<Predicate> predicates = new ArrayList<>(); 
for(Integer lcId : licenceClassIdList) { 
    SetJoin<DriversLicence, LicenceClass> dlClasses = dlRoot.join(DriversLicence_.licenceClasses); 
    predicates.add(builder.equal(dlClasses.get(LicenseClass_.id), lcId)); 
} 
Predicate predicate = builder.and(predicates.toArray(new Predicate[predicates.size()])); 

Aviso dlRoot es objeto de la clase de raíz y se puede obtener de la clase CriteriaQuery.Predicado resuelto es lo que está buscando ...

Cuestiones relacionadas