Отношения OneToMany не работают
Мои таблицы:
Продукт: id, name
Предложение: id, value, product_id
Entities:
@Entity
@Table(name="product")
public class Product implements Serializable {
@OneToMany(mappedBy="product")
private Set<Offer> offers;
...
}
@Entity
@Table(name="offer")
public class Offer implements Serializable {
@ManyToOne
@JoinColumn(name="PRODUCT_ID")
private Product product;
...
}
Когда я пытаюсь получить некоторые данные из таблицы Product
, я получаю a java.lang.NullPointerException
, и этот код: product.getOffers()
возвращает:
{IndirectSet: не экземпляр}
Как это исправить?
Ответы
Ответ 1
Это сообщение not. Команда print приводит к тому, что toString() вызывается в базовом IndirectSet.
TopLink поместит IndirectSet в переменную экземпляра, когда содержащий объект домена, считывается из базы данных. С первым сообщение, отправленное в IndirectSet, содержимое извлекается из базы данных и нормального поведения.
IndirectCollection типы специально реализованы, чтобы не создавать экземпляры на toString():
Для целей отладки #toString() не запускает чтение базы данных.
Однако любой другой вызов косвенного сбора, например, size() или isEmpty(), будет создавать экземпляр объекта.
Чтение базы данных в конечном счете запускается, когда один из "делегированных" методы делают первый вызов getDelegate(), который, в свою очередь, вызывает buildDelegate(), который отправляет сообщение getValue() в держатель значений. Держатель значений выполняет чтение базы данных. С первым сообщение, отправленное в IndirectSet, содержимое извлекается из базы данных и нормального поведения.
См. также IndirectList: не создается
Ответ 2
Если вы получаете {IndirectSet: not instantiated}
при доступе к product.getOffers()
, чем, скорее всего, вы выполняете этот код за пределами транзакции.
По умолчанию отношения @OneToMany
и @ManyToMany
lazy загружаются, что означает, что для лучшей производительности вы получите только данные когда вы хотите получить к нему доступ в первый раз. Это должно произойти в рамках активной транзакции.
Если вы не получите доступ к этим данным в этой области, то вы больше не сможете получить доступ к этим данным. Вы должны либо поместить свой код вызова в активную транзакцию, либо изменить коллекцию eager вместо ленивого:
@OneToMany(mappedBy="product", fetch=FetchType.EAGER)
Ответ 3
Вот что я сделал
// force load of the set.
entity.getSecrets().isEmpty();
System.out.println(entity.getSecrets());