2010-06-08 18 views
11

mam model danych, który wygląda mniej więcej tak:Hibernacja kwerendy dla wielu elementów w kolekcji

public class Item { 
    private List<ItemAttribute> attributes; 
    // other stuff 
} 

public class ItemAttribute { 
    private String name; 
    private String value; 
} 

(to oczywiście upraszcza dala dużo obcego materiału)

co chcę zrobić to stwórz zapytanie, aby poprosić o wszystkie przedmioty z jednym LUB WIĘCEJ konkretnych atrybutów, idealnie połączone z dowolnymi AND i OR. W tej chwili trzymam to prosto i próbuję zaimplementować przypadek ORAZ. W pseudo-SQL (lub pseudo-HQL jeśli będzie), to byłoby coś takiego:

select all items 
where attributes contains(ItemAttribute(name="foo1", value="bar1")) 
AND attributes contains(ItemAttribute(name="foo2", value="bar2")) 

przykładów w docs Hibernate nie wydaje się do rozwiązania tego konkretnego przypadku użycia, ale wydaje się dość wspólny. Sprawa alternatywą byłoby również przydatne, zwłaszcza tak mogę określić listę możliwych wartości, tj

where attributes contains(ItemAttribute(name="foo", value="bar1")) 
OR attributes contains(ItemAttribute(name="foo", value="bar2")) 
-- etc. 

Oto przykład, który działa OK dla jednego atrybutu:

return getSession().createCriteria(Item.class) 
     .createAlias("itemAttributes", "ia") 
     .add(Restrictions.conjunction() 
      .add(Restrictions.eq("ia.name", "foo")) 
      .add(Restrictions.eq("ia.attributeValue", "bar"))) 
     .list(); 

Uczenie się, jak to zrobić pójdzie długą drogę w kierunku poszerzenia mojej wiedzy na temat potencjału Hibernate. :)

+0

Odpowiedź tutaj działa: http://stackoverflow.com/questions/4834372/hibernate-criteria-on-collection-values ​​ – Taylor

Odpowiedz

0
SELECT item FROM Item item JOIN item.attributes attr 
    WHERE attr IN (:attrList) GROUP BY item 

a następnie w kodzie 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); 
+0

Wygląda na to, że adresuje on przypadek OR (tzn. Produkt ma co najmniej jedną Atrybut Elementów określony w attrList), ale co z przypadkiem AND ? Czy będzie to coś w rodzaju: GDZIE attr1 w pozycji. Atrybuty I atTR2 w pozycji. Atrybuty itd. ? Czy to ma nawet sens w Hibernate? – aarestad

+0

Ponadto, wydaje mi się, że uzyskuję ślad stosu podczas próby wykonania powyższego. Błąd główny: Powodowany przez: java.lang.IllegalArgumentException: Nie można ustawić pola java.lang.Integer com.mycompany.domain.ImmutableDomainEntity.id do java.util.ArrayList – aarestad

+0

Otrzymujesz błąd, ponieważ próbujesz ustawić alias zestawu (ItemAttributes) w pojedynczą encję (attr). Możesz użyć tylko klauzuli IN z pojedynczą jednostką. Lepszym (roboczym) sposobem byłoby odwrócenie zapytania: "WYBIERZ a.item z ItemAttribute a WHERE a.name IN (: attrlist)" - brak wyraźnego JOIN jest wymagany, jeśli właściwie odwzorowałeś relacje. –

0

Dlaczego nie następujące prace?

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(); 

To byłoby (name=foo1 && attributeValue=bar1) OR (name=foo2 && attributeValue=bar2)

+0

Może to działać dla rozwiązania, ale wersja conjunction, w której użyłbym Restrictions.and() nie działała. – aarestad

+0

Tak, ponieważ oznaczałoby to, że "WHERE x = 1 AND x = 2" zasadniczo, co nie zwróci żadnych wyników. Nie mogę wymyślić sposób, aby zrobić przypadku koniunkcji w surowym SQL. Być może trzeba będzie załadować przypadek rozłączności, a następnie zawęzić to za pomocą logiki aplikacji. – Andy

0

nie testowałem, ale jest to w jaki sposób należy spróbować rozwiązać problem, jeśli musiałbym:

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(); 

Proszę, pozwól mi wiem, czy zadziałało. Myślę, że to samo powinno działać z lub() ...

1

Czy możesz to zrobić za pomocą aliasingu?

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"))) 

Nie wiesz, jak hibernacyjne uchwyty łączą się na tej samej właściwości dwa razy jawnie, może warto spróbować?

+1

Otrzymuję org.hibernate.QueryException: duplikat ścieżki asocjacji: itemAttributes – Taylor

0

Zastosowanie LEFT_OUTER_JOIN aby zapobiec "gdzie x = 1 i x = 2" rodzaj problemu

CreateAlias ​​("itemAttributes", "ia", JoinType.LEFT_OUTER_JOIN)

Powiązane problemy