Запрос 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)