Hibernate лениво загруженные коллекции и PropertyChangeSupport - PullRequest
2 голосов
/ 09 сентября 2011

У меня есть объект, который лениво инициализирует Set, и я также добавил PropertyChangeSupport в этот класс объектов.Вот как выглядит сеттер для Set:

public void setAskPrices(Set<AskPrice> askPrices) {
    propertyChangeSupport.firePropertyChange(ASKPRICES_PROPERTY, this.askPrices,
            this.askPrices = askPrices);
}

В какой-то другой момент в моем коде я создаю запрос Criteria и хочу, чтобы он охотно выбирал эту коллекцию:

List<PriceRequest> pr = session.createCriteria(PriceRequest.class)
                        .setFetchMode("askPrices", FetchMode.JOIN)
                        .add(Restrictions.ilike("reqNum", "%" + reqNum + "%")).list();

Когда я запускаю запрос выше, я получаю исключение в Hibernate:

Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:122)
at org.hibernate.collection.PersistentSet.size(PersistentSet.java:162)
at java.util.AbstractSet.equals(AbstractSet.java:75)
at java.beans.PropertyChangeSupport.firePropertyChange(PropertyChangeSupport.java:273)
at com.frc_agencies.model.persistent.PriceRequest.setAskPrices(PriceRequest.java:160)

После копания я обнаружил, что функция firePropertyChange () вызывает oldValu.equals (newValue).В моем случае newValue - это новый постоянный Set.Функция equals () в некоторой точке вызывает size () для нового Set, который, в свою очередь, вызывает org.hibernate.collection.AbstractPersistentCollection.readSize (), который выглядит так:

protected boolean readSize() {
    if (!initialized) {
        if ( cachedSize!=-1 && !hasQueuedOperations() ) {
            return true;
        }
        else {
            throwLazyInitializationExceptionIfNotConnected();
            CollectionEntry entry = session.getPersistenceContext().getCollectionEntry(this);
            CollectionPersister persister = entry.getLoadedPersister();
            if ( persister.isExtraLazy() ) {
                if ( hasQueuedOperations() ) {
                    session.flush();
                }
                cachedSize = persister.getSize( entry.getLoadedKey(), session );
                return true;
            }
        }
    }
    read();
    return false;
}

Исключение составляетброшенный в throwLazyInitializationExceptionIfNotConnected ().Вызывает следующий метод:

/**
 * Is the collection currently connected to an open session?
 */
private final boolean isConnectedToSession() {
    return session!=null && 
            session.isOpen() &&
            session.getPersistenceContext().containsCollection(this);
}

Возвращает false на session.getPersistenceContext (). ContainsCollection (this);Поэтому по какой-то причине постоянный сбор не является частью текущего сеанса.

Я решил провести эксперимент.Я удалил вызов setFetchMode () для запроса Criteria, и просто после того, как запрос на запрос вернулся, я позвонил:

Hibernate.initialize(pr.getAskPrices());

И это, кажется, работает нормально!

Но я нехочу постоянно вызывать Hibernate.initialize ().Может кто-нибудь предложить, что я могу сделать, чтобы сделать эту работу, используя мой оригинальный вызов setFetchMode ()?

Спасибо.

Редактировать: Отправка соответствующего отображения

<set name="askPrices" table="ASK_PRICE" inverse="true" lazy="true" fetch="select" cascade="all-delete-orphan">
    <meta attribute="bound">ASKPRICES_PROPERTY</meta>
    <key on-delete="cascade">
        <column name="REQ_ID" not-null="true" />
    </key>
    <one-to-many class="AskPrice" />
</set>

Ответы [ 2 ]

0 голосов
/ 10 октября 2013

Для меня сработало немедленное превращение набора в коллекцию другого типа:

    List listOfObjects =  new ArrayList(aMethod.getASetOfObjects());

Мы застряли, используя старую версию Hibernate. Поэтому я предполагаю, что в коде Hibernate есть ошибка. Немедленно создав другую коллекцию java, он копирует объект в (энергонезависимую) физическую память, а не в кибернетический кеш.

Таким образом, исходный вопрос разрешится примерно так:

    List this.askPrices = new ArrayList(askPrices)

Надеюсь, это поможет.

0 голосов
/ 21 сентября 2011

Когда вы устанавливаете this.askprice = askprice, вы делаете свой this.askprice не постоянным, поэтому следующий оператор с сеансом сгенерирует отложенное исключение.Вы можете изменить свой lazy на false в отображении Xml (lazy = "false"), что является плохой практикой, которую я использую, или можно попробовать использовать Spring и Hibernatetemplate, это может решить проблему.

...