الاستعلام عن علاقة Manytomany مع معايير السبات
-
06-07-2019 - |
سؤال
لست متأكدًا من كيفية وصف هذه المشكلة ، لذلك أعتقد أن مثالًا هو أفضل طريقة لطرح سؤالي:
لدي جدولين مع وجود علاقة anmaltomany:
السائقين <-> licenceclass
LicenceClass هي أشياء مثل "Car" و "Motorbike" و "Medium Rigid".
باستخدام معايير السبات ، كيف يمكنني العثور على جميع التراخيص التي تحتوي على كل من "السيارة" و "الدراجات النارية"؟
تحديث 12/11/2008 لقد اكتشفت أنه يمكن تحقيق ذلك بسهولة باستخدام النتيجة المخصصة. ومع ذلك ، فإن المشكلة هي أن محول النتائج يتم تطبيقه فقط بعد أن يعيد الاستعلام نتائجه ، فإنه لا يصبح في الواقع جزءًا من SQL. لذلك أعتقد أن سؤالي هو الآن "هل يمكنك فعل ما وصفته في البداية في SQL - وهل هناك معايير السبات التناظرية؟"
المحلول
إليكم كيف حققتها أخيرًا باستخدام 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();
}
أو باستخدام معايير السبات مع 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 هو اسم الجدول الذي ينشئه السبات لدعم العلاقة بين العديد من السائقين و licenceclass.
نصائح أخرى
لا يزال بإمكانك استخدام ترميز DOT للعمل عبر العلاقات. على سبيل المثال ، على افتراض أن لديك سائقة.
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<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()]));
إشعار dlroot هو كائن فئة الجذر ويمكنك الحصول عليه من فئة المعايير. ناتج عن ما تبحث عنه ...
'I don't think this going to work. I want to find all licences that have both "Car" and "Motorbike" '
User Expression.and(....) instead of Expression.or(....) in the snippet provided by Nick