Как отобразить пользовательский набор в JPA?

У меня есть проблемы в отображении пользовательского набора с JPA (Поставщик Hiberante). Например, когда я использую объект с атрибутом

List<Match> matches;

с

<one-to-many name="matches">
    <cascade>
        <cascade-all />
    </cascade>
</one-to-many>

в моем файле ORM это в порядке; Но если я заменяю "Соответствия списка";

private Matches matches;

, где "Соответствия" определяются как:

public class Matches extends ArrayList<Match> {

    private static final long serialVersionUID = 1L;
}

Это производит следующую ошибку:

Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: by.sokol.labs.jpa.MatchBox.matches

Спасибо за Ваше внимание!

9
задан Denis 3 July 2010 в 23:32
поделиться

2 ответа

Можно, но вы должны ссылаться на него как на одну из общих коллекций - List или Set.

итак:

private List matches = new Matches();

Почему? Потому что Hibernate создает прокси для ваших коллекций, чтобы, например, обеспечить ленивую загрузку. Поэтому он создает PersistentList, PersistentSet и PersistentBag, которые являются List, но не являются Matches. Поэтому, если вы хотите добавить дополнительные методы к этой коллекции - ну, вы не можете.

Посмотрите эту статью для более подробной информации.

Однако у вас есть решение. Не используйте наследование, используйте композицию. Вы можете, например, добавить в вашу сущность метод getMatchesCollection() (в дополнение к традиционному getter), который выглядит так:

 public Matches getMatchesCollection() {
    return new Matches(matches);
 }

А ваш класс Matches будет выглядеть так (используя google-collections' ForwardingList):

public class Matches extends ForwardingList {
    private List<Match> matches;
    public Matches(List<Match> matches) { this.matches = matches; }
    public List<Match> delegate() { return matches; }
    // define your additional methods
}

Если вы не можете использовать google-коллекции, просто определите ForwardingList самостоятельно - он вызывает все методы базового List

Если вам не нужны дополнительные методы для работы со структурой, то не определяйте пользовательскую коллекцию.

7
ответ дан 3 November 2019 в 00:58
поделиться

Hibernate требует, чтобы постоянные поля со значениями коллекции были объявлены как тип интерфейса (потому что они будут заменены реализацией Hibernate для целей отложенной загрузки). Из справочной документации:

6.1. Постоянные коллекции

Hibernate требует, чтобы постоянные поля, содержащие коллекцию, были объявлены как тип интерфейса. Например:

 общедоступный класс Продукт {
private String serialNumber;
частные части набора = новый HashSet ();

public Set getParts () {возвращать части; }
void setParts (Установить части) {this.parts = parts; }
общедоступная строка getSerialNumber () {return serialNumber; }
void setSerialNumber (String sn) {serialNumber = sn; }
}

Фактический интерфейс может быть java.util.Set , java.util.Collection , java.util.List , java.util.Map , java.util.SortedSet , java.util.SortedMap или что-нибудь еще нравится ("все, что угодно" означает, что вы придется написать реализацию из org.hibernate.usertype.UserCollectionType .)

Обратите внимание, как переменная экземпляра была инициализирован экземпляром HashSet . Это лучший способ инициализировать коллекцию с оценкой свойства вновь созданных (непостоянные) экземпляры. Когда ты сделать экземпляр постоянным, вызов persist () , например, Hibernate фактически заменит HashSet с экземпляром Собственная реализация Hibernate Set .

Итак, ваш второй подход невозможен, по крайней мере, так, как вы его заявили. Но, честно говоря, я не вижу в этом смысла.

4
ответ дан 3 November 2019 в 00:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: