Спящий режим @One-To-Many похож на @ElementCollection

Я пытаюсь сделать что-то подобное, но использую @One-To-Many вместо @ElementCollection.

public class Book {
    ...
    @ElementCollection
    Set<String> tags;
    ...
}

Это создает две таблицы, одну для книги и одну для тегов с (BookID, тег), которые отлично работают, за исключением того факта, что я не могу использовать критерии с @ElementCollection.

Поэтому я изменил его и сделал класс-оболочку для тегов:

public class Book {
    ...
    @OneToMany(...)
    Set<BookTag> tags;
    ...
}


public class BookTag {
    ...
    String tag;
    ...
}

Проблема в том, что использование аннотации @OneToMany в спящем режиме создает 3 таблицы: одну для книг, одну для тегов и одну для объединения книг и тегов. Это решение отлично работает, но я хотел бы иметь 2 таблицы вместо 3, поскольку класс Tag содержит только строку.

Есть ли способ использовать @OneToMany и заставить hibernate создавать 2 таблицы, как это делается с @ElementCollection?


person LorenzoR    schedule 27.06.2012    source источник
comment
Вы уверены, что не можете использовать коллекции элементов в запросах критериев? У нас есть как минимум один ответ, который говорит об обратном.   -  person Tom Anderson    schedule 28.06.2012
comment
В моем случае с ElementCollection я получил org.hibernate.MappingException: коллекция не была ассоциацией. Затем я прочитал это и подумал, что не могу использовать ElementClection и ElementCollection.   -  person LorenzoR    schedule 01.07.2012
comment
Интересный. Вероятно, некоторые типы запросов можно выполнять с коллекциями элементов, а некоторые нет. Какой запрос вы пытаетесь сделать?   -  person Tom Anderson    schedule 01.07.2012
comment
Мне нужно перечислить все коробки, которые содержат определенный тег.   -  person LorenzoR    schedule 02.07.2012


Ответы (2)


Да, указав, что OneToMany должен использовать столбец соединения вместо столбца по умолчанию (который использует таблицу соединения):

@OneToMany(...)
@JoinColumn(name = "BOOK_ID")
private Set<BookTag> tags;
person JB Nizet    schedule 27.06.2012

Вы можете сделать этот запрос на @ElementCollection с критериями JPA. Предполагая, что вы используете метамодель, это выглядит так:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Book> cq = cb.createQuery(Book.class);
Root<Book> book = cq.from(Book.class);

cq.select(book).where(cb.equal(book.join(Book_.tags), "fanfic"));

TypedQuery<Book> query = em.createQuery(cq);

Если вы не используете метамодель, она практически такая же, но вам, вероятно, придется использовать joinSet.

Этот запрос имеет разумный смысл. Единственным удивительным моментом является необходимость делать join, а не get, потому что tags является свойством во множественном числе, а не в единственном числе, но вы смотрите на отдельные его элементы.

Вы также можете ожидать, что более естественное чтение

cq.select(book).where(cb.isMember("fanfic", book.get(Book_.tags)));

должно сработать. Возможно, с некоторыми реализациями JPA это так. Но с Hibernate (4.1.4) это не так; он взрывается синтаксической ошибкой. Похоже, это ошибка Hibernate HHH-5209.

person Tom Anderson    schedule 06.07.2012