Hibernate 延迟初始化帮助

发布于 2024-08-05 03:54:21 字数 1798 浏览 10 评论 0原文

我在尝试使用休眠删除时遇到问题。当我尝试删除时,出现异常,提示存在子项并且存在 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);
} 

我真的不知道我做错了什么。我没有非常复杂的模式,只有一张产生子项(国家)的表。我有什么想法可以解决这个问题吗?

I have an issue trying to delete using hibernate. When I try to delete I get an exception saying that children exist and there is a FK violation. I want to delete the children also but the delete doesn't seem to be cascading. After about a week of trying to fix this issue I read that I should be using HibernateInterceptor to keep the session open so that the children can be loaded. When I try to do this now I get the following error:

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

Here is the extract from my mapping file:

<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>

Here is an extract from the application context:

<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>

Here is the method in my 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);
} 

I really don't know what I am doing wrong. I do not have a very complex schema, just one table that results in children (countries). Any ideas what I could do to fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤独难免 2024-08-12 03:54:21

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

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

当然,这假设适当的映射/级联到位。设置您显示的映射摘录是可以的,但 设置除外。由于以下几个原因,它相当棘手:

  1. 您的数据库必须支持它并且您的模式必须定义它。如果不是这种情况,您将会收到错误。
  2. 如果级联设置为“ALL”,则使用此设置不会获得任何性能改进,因为 Hibernate 将仍然加载每个子实体以检查进一步的关联。您需要将级联设置为“保存更新”才能使其正常工作,这会对托管生命周期的父子关系产生副作用。

因此,我建议暂时删除 on-delete="cascade" 并且在您完全理解所有含义之前不要使用它。

您提到的 HibernateInterceptor 与所有这些无关(最肯定与您编码的 delete() 方法无关);它是与 UI 层通信的 open-session-in-view 方法的一部分。

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

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

If you simply want to delete parent along with children, you do NOT need to load the children collection. You don't even need to get() the parent, using load() is enough:

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

This, of course, assumes the appropriate mapping / cascade in place. Set mapping excerpt you've shown is OK with exception of <key ... on-delete="cascade"/> setting. It's rather tricky for several reasons:

  1. Your database must support it and your schema must define it. You'll get an error if that's not the case.
  2. You will NOT get any performance improvements with this setting if cascade is set to "ALL" because Hibernate would still load each child entity to check for further associations. You need to set cascade to "save-update" in order for this to work, which then has side effects for parent-child relationship with managed lifecycle.

I would therefore suggest to remove on-delete="cascade" for now and to not use it in general until you completely understand all the implications.

HibernateInterceptor you've mentioned has nothing to do with all of this (most certainly not with the delete() method as you have it coded); it's part of open-session-in-view approach to communication with UI layer.

Here's how to troubleshoot all of the above:

  1. Get rid of HibernateInterceptor for now.
  2. Write a unit test to create parent / children in one transaction, commit it, delete them in 2nd transaction, commit it.
  3. If (2) doesn't work, you have a problem with your mapping and / or schema. Post both here and I'll take a look.
  4. If (2) does work and your delete() method above does not work, you have a problem somewhere in your code where delete() is invoked. Perhaps you're loading that same Communication instance and overwriting its communicationCountries collection.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文