středa 14. ledna 2009

Hibernate Collection Of Elements a Criteria API

Navykl jsem si používat Hibernatovský CollectionOfElements ve spojení s Java 5 enumy. Collection of elements je zjednodušený vztah one-to-many, na jehož druhém konci není entita (s příslušnou tabulkou), ale jednoduchý typ jako string nebo enum.
Například mám předmět, u kterého chci mít zaznamenané jeho barvy (může mít víc barev). Barvy jsou jasně a pevně dané, není potřeba na ně mít v databázi číselníkovou tabulku.

public enum Color {
   RED, GREEN, BLUE, ...
}

@Entity
public class Item {
  @CollectionOfElements(targetElement=Color.class)
  @Enumerated(EnumType.STRING)
  protected Set<Color> color = EnumSet.noneOf(Color.class);
  ...
}

Tím pádem  mám v databázi jen "vazební" tabulku item_color se sloupečky id (primární klíč a zároveň cizí klíč do item) a element, kam jsou jako stringy serializované barvy.
Potud ideální. Pokud laskavý čtenář nehodlá používat Criteria API, může odejít spokojen. V opačném případě může zakusit něco horkých chvil a pokud nečte FAQ, tak i dost beznaděje, protože pokus o vytvoření Criteria k vybrání předmětů dané barvy skončí totiž výjimkou org.hibernate.MappingException: collection was not an association.
Ve FAQ se totiž praví, že Criteria API a Collection of Elements nelze. Ne že by samotné přečtení tohoto smutného faktu situaci vylepšilo... Na tento problém existuje záznam v Jira a dobrotivý přispěvatel mě navedl na řešení.

Vrátíme se zpět k SQL:
session.createCriteria(Item.class).add(Restrictions
  .sqlRestriction("{alias}.id in (select item_id from item_color where {alias}.id=item_id and element=?)", 
     i.name(), Hibernate.STRING));

1 komentář: