Как отобразить пользовательскую коллекцию в JPA? - PullRequest
9 голосов
/ 04 июля 2010

У меня проблемы с отображением пользовательской коллекции с помощью 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

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

Ответы [ 2 ]

7 голосов
/ 04 июля 2010

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

так:

private List matches = new Matches();

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

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

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

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

И ваш Matches класс будет выглядеть (используя google-collection '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

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

4 голосов
/ 04 июля 2010

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

6,1. Постоянные коллекции

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

public class Product {
    private String serialNumber;
    private Set parts = new HashSet();

    public Set getParts() { return parts; }
    void setParts(Set parts) { this.parts = parts; }
    public String 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.

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

...