Запрос Hibernate для нескольких элементов в коллекции
У меня есть модель данных, которая выглядит примерно так:
public class Item {
private List<ItemAttribute> attributes;
// other stuff
}
public class ItemAttribute {
private String name;
private String value;
}
(это, очевидно, упрощает многие посторонние вещи)
Что я хочу сделать, так это создать запрос, чтобы спросить все элементы с одним или несколькими конкретными атрибутами, идеально связанными с произвольными символами AND и OR. Сейчас я держу его простым и просто пытаюсь реализовать случай И. В псевдо-SQL (или псевдо-HQL, если вы бы), это было бы что-то вроде:
select all items
where attributes contains(ItemAttribute(name="foo1", value="bar1"))
AND attributes contains(ItemAttribute(name="foo2", value="bar2"))
Примеры в документах Hibernate, похоже, не рассматривали этот конкретный вариант использования, но он кажется довольно распространенным. Случай дизъюнкции также был бы полезен, тем более, что я мог бы указать список возможных значений, т.е.
where attributes contains(ItemAttribute(name="foo", value="bar1"))
OR attributes contains(ItemAttribute(name="foo", value="bar2"))
-- etc.
Вот пример, который работает нормально для одного атрибута:
return getSession().createCriteria(Item.class)
.createAlias("itemAttributes", "ia")
.add(Restrictions.conjunction()
.add(Restrictions.eq("ia.name", "foo"))
.add(Restrictions.eq("ia.attributeValue", "bar")))
.list();
Обучение тому, как это сделать, будет иметь большое значение для расширения моего понимания потенциала гибернации.:)
Ответы
Ответ 1
Не могли бы вы использовать aliasing для этого?
Criteria itemCriteria = session.createCriteria(Item.class);
itemCriteria.createAlias("itemAttributes", "ia1")
.createAlias("itemAttributes", "ia2")
.add(Restrictions.eq("ia1.name", "foo1"))
.add(Restrictions.eq("ia1.attributeValue", "bar1")))
.add(Restrictions.eq("ia2.name", "foo2"))
.add(Restrictions.eq("ia2.attributeValue", "bar2")))
Не знаете, как спящий режим соединяется с одним и тем же свойством дважды явно, возможно, стоит попробовать?
Ответ 2
SELECT item FROM Item item JOIN item.attributes attr
WHERE attr IN (:attrList) GROUP BY item
а затем в коде Java:
List<ItemAttribute> attrList = new ArrayList<ItemAttribute>();
attrList.add(..); // add as many attributes as needed
...// create a Query with the above string
query.setParameter("attrList", attrList);
Ответ 3
Почему бы не выполнить следующие действия?
return getSession().createCriteria(Item.class)
.createAlias("itemAttributes", "ia")
.add(Restrictions.or()
.add(Restrictions.conjunction()
.add(Restrictions.eq("ia.name", "foo1"))
.add(Restrictions.eq("ia.attributeValue", "bar1")))
.add(Restrictions.conjunction()
.add(Restrictions.eq("ia.name", "foo2"))
.add(Restrictions.eq("ia.attributeValue", "bar2"))))
.list();
Это будет (name=foo1 && attributeValue=bar1) OR (name=foo2 && attributeValue=bar2)
Ответ 4
Я не тестировал его, но я должен попытаться решить вашу проблему, если мне придется:
Map<String,String> map1 = new TreeMap<String,String>();
map1.put("ia.name","foo1");
map1.put("ia.value","bar1");
Map<String,String> map2 = new TreeMap<String,String>();
map2.put("ia.name","foo2");
map2.put("ia.value","bar2");
return getSession().createCriteria(Item.class)
.createAlias("itemAttributes", "ia")
.add(Restrictions.and()
.add(Restrictions.allEq(map1))
.add(Restrictions.allEq(map2))
)
.list();
Пожалуйста, дайте мне знать, если это сработает. Я думаю, что то же самое должно работать с (или)...
Ответ 5
Используйте LEFT_OUTER_JOIN, чтобы предотвратить проблему типа "WHERE x = 1 AND x = 2"
CreateAlias ( "itemAttributes", "ia", JoinType.LEFT_OUTER_JOIN)