У меня есть проблемы в отображении пользовательского набора с 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
Спасибо за Ваше внимание!
Можно, но вы должны ссылаться на него как на одну из общих коллекций - 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
Если вам не нужны дополнительные методы для работы со структурой, то не определяйте пользовательскую коллекцию.
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
с экземпляром Собственная реализация HibernateSet
.
Итак, ваш второй подход невозможен, по крайней мере, так, как вы его заявили. Но, честно говоря, я не вижу в этом смысла.