сопоставление аннотаций с двунаправленным OneToMany / ManyToOne не извлекается?

#java #hibernate

#java #переход в спящий режим

Вопрос:

Я явно пытаюсь понять это, поэтому помощь с благодарностью…

У меня есть следующее отображение:

 @Entity
@Table(name = "parent")
public class ParentEntity
{
...
    @Id
    @Column(name = "parent_id")
    private Long id;
...
    @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER)
    private List<ChildEntity> children;
...
}

@Entity
@Table(name = "child")
public class ChildEntity
{
...
    @Id
    @Column(name = "child_id")
    private Long id;
...
    @ManyToOne(fetch = FetchType.EAGER)
    @NotFound(action = NotFoundAction.IGNORE)
    @JoinColumn(name = "parent_id")
    private ParentEntity parent;
...
}
  

в моей базе данных у меня есть:

 parent
------
parent_id: 1

child
------
child_id: 1, parent_id: 1
  

Однако

 ((Parent) session.get(Parent.class, 1)).getChildren()
  

возвращает значение null.

кто-нибудь может увидеть, чего мне не хватает?

спасибо, p.

Редактировать

Кажется, что это больше связано с состоянием сеанса, поскольку коллекция не заполняется в контексте того же сеанса, но коллекция заполняется в следующем сеансе…

рассмотрим следующее:

 void setupRender()
{
    debug("existing not just added", (ParentEntity) session.get(ParentEntity.class, 13L));

    ParentEntity parent = new ParentEntity();
    session.save(parent);

    ChildEntity child = new ChildEntity();
    child.setParent(parent);
    session.save(child);

    debug("new one before commit", parent);

    sessionManager.commit();

    debug("new one after commit", parent);

    debug("new one after re-fetch", (ParentEntity) session.load(ParentEntity.class, parent.getId()));
}

private void debug(String prefix, ParentEntity parent)
{
    log.debug(prefix   ": parent id: "   parent.getId()   ", Children is "
              (parent.getChildren() == null ? "null" : "size:"   parent.getChildren().size()));
}
  

приводит к следующему выводу:

 DEBUG - existing not just added: parent id: 13, Children is size:1
DEBUG - new one before commit: parent id: 23, Children is null
DEBUG - new one after commit: parent id: 23, Children is null
DEBUG - new one after re-fetch: parent id: 23, Children is null
  

итак, если это связано с состоянием сеанса, и фиксации недостаточно для запуска повторной выборки, что мне нужно сделать, чтобы получить отображение для извлечения коллекции?

еще раз спасибо!

Комментарии:

1. Получаете ли вы какую-либо полезную информацию при просмотре данных отладки в режиме гибернации?

2. пожалуйста, смотрите Редактирование. Кстати, db — это postgres, я также нахожусь в среде tapestry, используя модуль tapestry-hibernate.

Ответ №1:

Да, фиксация не запускает обновление кэша сеанса.

Типичный подход здесь заключается в использовании шаблона «сеанс для каждого запроса», чтобы вы закрывали сеанс сразу после фиксации и открывали другой сеанс для следующих транзакций (хотя это не вариант, если вы используете шаблон «Открыть сеанс в представлении»).

Другой хорошей практикой, которая может помочь решить эту проблему, является одновременное изменение обеих сторон двунаправленной связи:

 public class ParentEntity {
    ...
    public void addChild(ChildEntity c) {
        children.add(c);
        c.setParent(this);
    }
}
  

Таким образом, вы можете сохранять объекты в кэше сеанса в согласованном состоянии.

Наконец, если вам действительно нужно обновить объект внутри сеанса, вы можете вызвать Session.refresh() для него.

Ответ №2:

Добавление каскадного атрибута как части вашего OneToMany в родительском объекте может решить проблему.

 @Entity
@Table(name = "parent")
public class ParentEntity
{
...
    @Id
    @Column(name = "parent_id")
    private Long id;
...
    @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER, cascade=CascadeType.ALL)
    private List<ChildEntity> children;
...
}
  

Затем для сохранения строки

 ParentEntity parent = new ParentEntity();

ChildEntity child = new ChildEntity();
child.setParent(parent);
parent.getChildren().add(child);
session.save(parent);
  

Это также приведет к удалению всех дочерних элементов при удалении родительского элемента.

Комментарии:

1. Правильно, но проблема не в этом 🙂

Ответ №3:

В вашем первоначальном вопросе подразумевалось, что данные уже существовали в базе данных до того, как вы открыли сеанс, это была важная информация, чтобы знать, что вы сохраняете ее в том же сеансе…

Кстати, вот официальное руководство по гибернации по этой теме: (взято из http://community.jboss.org/wiki/HibernateFAQ-CommonProblems )

У меня возникли проблемы с двунаправленной ассоциацией.

Когда вы обновляете двунаправленную ассоциацию, вы должны обновить оба конца.

 parent.getChildren().add(child);
child.setParent(parent);
  

Лучше всего сделать это в методе управления ассоциацией вашего постоянного класса.

У меня все еще проблемы!

Прочитайте документацию! В главе 16 справочной документации есть подробный раздел о «родительских / дочерних связях», включая примеры кода.

Комментарии:

1. Тот факт, что это список, не имеет значения. Кроме того, если getChildren() возвращает null, значит, Parent a успешно загружается, таким образом, чтение из базы данных, похоже, работает.

Ответ №4:

Решение, которое я использую на данный момент, заключается в инициализации коллекции вручную во время построения:

 private List<ChildEntity> children 
    = new ArrayList<ChildEntity>;
  

Я не уверен, что это хорошая практика, но это работает и просто.