Consultando a relação de muitos tomanos com os critérios de hibernação
-
06-07-2019 - |
Pergunta
Não tenho certeza de como descrever esse problema, então acho que um exemplo é a melhor maneira de fazer minha pergunta:
Eu tenho duas mesas com um relacionamento de muita tomana:
Driverslicence <-> licenceclass
Licenceclass é coisas como "carro", "motocicleta" e "médio rígido".
Usando os critérios de hibernação, como posso encontrar todas as licenças que possuem licencasses de "carro" e "motocicleta"?
ATUALIZAÇÃO 11/12/2008 Descobri que isso pode ser facilmente alcançado usando um resultante de resultado personalizado. No entanto, o problema é que um transformador de resultado é aplicado apenas após a consulta retornar seus resultados, na verdade não se torna parte do SQL. Então, acho que minha pergunta é agora "Você pode fazer o que descrevi inicialmente no SQL - e existe um analógico de critério de hibernação?"
Solução
Veja como finalmente consegui isso usando 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();
}
Ou usando os critérios de hibernato com um 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));
}
LECENCE_CLASS_JOIN_TABLE é o nome da tabela que o Hibernate gera para suportar a relação muitos para muitos entre o Driverslicence e o Licenceclass.
Outras dicas
Você ainda pode usar a notação do DOT para trabalhar nas relações. Por exemplo, supondo que você tenha uma propriedade DriverSlicence.licenceclass e propriedade LicEnceclass.type, então:
session.createCriteria(DriversLicence.class)
.add(Expression.or(
Expression.eq("licenceClass.type", "Car"),
Expression.eq("licenceClass.type", "Motorbike")
)
).list();
Pessoalmente, porém, eu simplesmente evitaria o uso de critérios neste caso, porque não é uma consulta dinâmica, mas, em vez disso, usará:
session.createQuery("from DriversLicence where licenceClass.type in (:types)")
.setParameterList("types", myListOfTypes)
.list();
Eu tive um problema semelhante, mas corrigi -me usando o HQL, tenho uma classe "Enterprise" relacionada à classe "usuário" e também relacionada à "função de classe", eles estão muitos para muitos relacionamentos, quando preciso de todas as empresas relacionadas Para um usuário específico, faço o seguinte;
Select e from Enterprise As e inner join e.Users As u inner join u.Roles As r
Where u.UserCode=?
Suponho que, no seu caso, você deve fazer 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 ajude.
Outra opção é fazer as junções de corrente (uma junção por cada Licenseclass). Eu usei o construtor de critérios e predicados como este
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()]));
Observe que o dlroot é objeto da classe raiz e você pode obtê -la da classe de critério. O predicado resultado é o que você está procurando ...
'Eu não acho que isso vai funcionar. Eu quero encontrar todas as licenças que têm Ambas "Carro" e "motocicleta" '
Expressão do usuário. E (....) em vez de expressão.or (....) no trecho fornecido por nick