У меня есть модель данных, которая выглядит примерно так:
public class Item {
private List<ItemAttribute> attributes;
// other stuff
}
public class ItemAttribute {
private String name;
private String value;
}
(это, очевидно, упрощает далеко много постороннего материала),
То, что я хочу сделать, создают запрос для просьбы все Объекты с ОДНИМ ИЛИ НЕСКОЛЬКИМИ конкретными атрибутами, к которым идеально присоединяются с произвольным ANDs и ORs. Прямо сейчас я сохраняю это простым и просто пытаюсь реализовать И случай. В псевдо-SQL (или pseudo-HQL, если бы Вы были бы), это было бы что-то как:
select all items
where attributes contains(ItemAttribute(name="foo1", value="bar1"))
AND attributes contains(ItemAttribute(name="foo2", value="bar2"))
Примеры в Быть в спящем режиме документах, казалось, не обратились к этому конкретному варианту использования, но он походит на довольно общий. Случай разъединения также был бы полезен, особенно таким образом, я мог указать список возможных значений, т.е.
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();
При изучении, как сделать, это пошло бы длинными путями к расширению моего понимания потенциала Hibernate.:)
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);
Почему следующее не сработает?
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)
Я не проверял это, но вот как я должен попытаться решить вашу проблему, если бы мне пришлось:
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();
Пожалуйста, дайте мне знать, если это сработало. Я думаю, то же самое должно работать с or()...
Можете ли вы использовать 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")))
Не уверен, как hibernate обрабатывает присоединение к одному и тому же свойству дважды явным образом, может быть, стоит попробовать?
.