用Hibernate Criteria查询ManyToMany关系

我不确定如何描述这个问题,所以我认为一个例子是提出问题的最佳方式:

我有两个表与manyToMany关系:

DriversLicence LicenceClass

LicenceClass是“Car”,“Motorbike”和“Medium Rigid”之类的东西。

使用Hibernate Criteria,我怎样才能找到同时拥有“Car”和“Motorbike”LicenceClasses的所有许可证?

更新12/11/2008我发现使用自定义ResultTransformer可以轻松实现这一点。 但问题是结果转换器仅在查询返回其结果后才应用,它实际上不会成为SQL的一部分。 所以我想我现在的问题是“你能做我最初在SQL中描述的内容吗?是否有Hibernate Criteria模拟?”

以下是我最终使用HQL实现它的方法:

public List findDriversLicencesWith(List 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(); } 

或者使用带有sqlRestriction的Hibernate Criteria:

 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是hibernate生成的表的名称,用于支持driversLicence和LicenceClass之间的多对多关系。

您仍然可以使用点符号来处理关系。 例如,假设您有DriversLicence.licenceClass属性和LicenceClass.type属性,则:

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

就个人而言,我只是避免在这种情况下使用标准,因为它不是动态查询,而是使用:

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

我有一个类似的问题,但修复了使用HQL,我有一个类“企业”,与类“用户”相关,也与类“角色”有关,他们干涉多对多关系,当我需要所有相关的企业对于特定用户,我执行以下操作;

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

我想在你的情况下你应该做的事情;

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

希望能帮助到你。

另一种选择是链接(每个LicenseClass一个连接)。 我使用了像这样的标准构建器和谓词

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

注意dlRoot是Root类的对象,你可以从CriteriaQuery类中获取它。 结果谓词是你在寻找什么…

“我不认为这会发挥作用。 我想找到所有同时包含 “Car”和“Motorbike”的许可证

用户表达式和。(….)代替尼克提供的片段中的Expression.or(….)