Hibernate延迟初始化帮助

时间:2009-09-21 16:40:06

标签: java database hibernate spring spring-aop

我尝试使用hibernate删除时遇到问题。当我尝试删除时,我得到一个异常,说孩子存在并且存在FK违规。我想删除孩子,但删除似乎没有级联。在尝试修复此问题大约一周后,我读到我应该使用HibernateInterceptor来保持会话打开,以便可以加载子进程。当我尝试这样做时,我收到以下错误:

Failed to load portlet com.blah.blah.CommunicationsPortlet: java.lang.ClassCastException: $Proxy27 incompatible with com.blah.blah.HibernateCommunicationsDAOImpl

以下是我的映射文件的摘录:

<set name="communicationCountries" inverse="true" cascade="all,delete-orphan">
<key column="COM_ID" not-null="true" on-delete="cascade" />
<one-to-many class="com.blah.blah.CommunicationCountry"/>
</set>

以下是应用程序上下文的摘录:

<bean id="hibernateCommunicationsDAOImplTarget"
class="com.blah.blah.dao.impl.HibernateCommunicationsDAOImpl">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>

<bean id="hibernateCommunicationsDAOImpl" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target"><ref bean="hibernateCommunicationsDAOImplTarget"/></property>
<property name="proxyInterfaces">
<value>com.blah.blah.dao.CommunicationsDAO</value>
</property>
<property name="interceptorNames">
<list>
<value>hibernateInterceptor</value>
</list>
</property>
</bean>

以下是我的DAO中的方法:

public void deleteCommunication(Integer id) throws DataAccessException
{
HibernateTemplate hibernate = getHibernateTemplate();
Communication existing = (Communication)hibernate.get(Communication.class, id);
hibernate.initialize( existing.getCommunicationCountries());
hibernate.delete(existing);
} 

我真的不知道我做错了什么。我没有非常复杂的架构,只有一个表导致子(国家/地区)。我有什么想法可以解决这个问题吗?

1 个答案:

答案 0 :(得分:3)

如果您只想删除父项以及子项,则无需加载子项集合。你甚至不需要get()父母,使用load()就足够了:

public void deleteCommunication(Integer id) throws DataAccessException {
  HibernateTemplate hibernate = getHibernateTemplate();
  Communication existing = (Communication) hibernate.load(Communication.class, id);
  hibernate.delete(existing);
}

当然,这假设适当的映射/级联。除<key ... on-delete="cascade"/>设置外,设置您显示的地图摘录即可。由于以下几个原因,它相当棘手:

  1. 您的数据库必须支持它,您的架构必须定义它。如果情况并非如此,你会收到错误。
  2. 如果级联设置为“ALL”,则此设置不会获得任何性能改进,因为Hibernate会仍然加载每个子实体以检查进一步的关联。您需要将级联设置为“save-update”才能使其正常工作,这会对托管生命周期的父子关系产生副作用。
  3. 因此,我建议暂时删除on-delete="cascade",并在完全理解所有含义之前不要使用它。

    你提到过的HibernateInterceptor与所有这些都没有关系(大多数情况下你没有使用delete()方法编码);它是open-session-in-view与UI层进行通信的方法的一部分。

    以下是解决上述所有问题的方法:

    1. 暂时摆脱HibernateInterceptor。
    2. 编写单元测试以在一个事务中创建父/子,提交它,在第二个事务中删除它们,然后提交它。
    3. 如果(2)不起作用,则表示您的映射和/或架构存在问题。在这里张贴,我会看看。
    4. 如果(2)确实有效且上面的delete()方法不起作用,则代码中的某个位置会出现调用delete()的问题。也许您正在加载相同的Communication实例并覆盖其communicationCountries集合。