Отношения 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());