Hibernate延迟加载集合和PropertyChangeSupport

3

我有一个实体,它懒惰地初始化了一个Set,并且我还为该实体类添加了PropertyChangeSupport。下面是Set的setter方法:

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是新的持久化集合。equals()函数会在某个时候对新的集合调用size(),然后size()会调用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);
}

当session.getPersistenceContext().containsCollection(this)返回false时,说明当前持久化集合不属于当前会话。

我决定进行一个实验。我删除了Criteria查询中的setFetchMode()调用,并且在查询调用返回后,我简单地调用了:

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>

请发布您的映射XML(或注释)。另外,请查看此错误报告。https://hibernate.onjira.com/browse/HHH-3524 - zmf
我已发布了相关的映射。那个错误似乎与此有关,即使我没有在实际关联上添加任何限制(仅在父对象上添加了限制)。 - Caleb
2个回答

1

对我而言有效的方法是立即将集合转换为另一种类型:

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

我们被迫使用较旧版本的Hibernate。因此,我的猜测是Hibernate代码存在错误。通过立即构建另一个Java集合,它将对象复制到(非易失性)物理内存中,而不是Hibernate缓存中。
因此,原始问题可以解决为类似以下内容:
    List this.askPrices = new ArrayList(askPrices)

希望这有所帮助。

0
当你设置this.askprice = askprice时,你使得你的this.askprice不具有持久性,因此下一个带有session的语句将抛出lazy异常。你可以在Xml映射中将lazy更改为false(lazy="false"),这是我正在使用的一种不好的做法,或者可以尝试使用Spring和Hibernatetemplate,这可能会解决问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接