java - hibernate 级联删除不起作用

标签 java database hibernate

我在尝试在 Hibernate 中执行删除时遇到问题。每次我尝试删除时,我都会遇到一个问题,因为存在子记录,因此无法删除父记录。我想删除 child 和 parent 。这是我的父映射:

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

这是子类的映射:

<many-to-one name="communication" column="COM_ID" not-null="true" class="com.fmr.fc.portlet.communications.vo.Communication" cascade="all"/>

编辑 - 当我插入时,数据被插入到父项和子项中。

当我使用具有我要修改的对象 ID 的新对象进行更新时,父对象会更新,但所有现有的子对象都会再次添加。我似乎无法删除 child 。当我使用 ID 检索对象并修改它时,我收到一条错误消息,告诉我 org.hibernate.LazyInitializationException:无法初始化代理 - 拥有 session 已关闭。我怀疑这是因为在一个 getHibernateTemplate() 调用中我获取了对象并将其保存在另一个调用中,这是两个不同的 session ?

当我执行删除操作时,我会收到错误消息,因为存在子项。我知道我只是在做一些完全愚蠢的事情,因为我不知道这一切是如何运作的。

这是我的更新和删除方法,在这种情况下,更新/保存是在保存之前检索和修改。删除使用的新对象与我要删除的数据库中的对象具有相同的 ID:

public void deleteCommunication(Communication comm) throws DataAccessException 
{
    getHibernateTemplate().delete(comm);
}

public void saveCommunication(Communication comm) throws DataAccessException
{       
    Communication existing = (Communication)getHibernateTemplate().load(Communication.class, comm.getComId());
    existing.getCommunicationCountries().clear();

    getHibernateTemplate().saveOrUpdate(existing);      
}

更新 所以这是我的新方法,但仍然没有快乐。我认为我的问题与 child 未加载/初始化等有关。虽然删除,但我无法理解为什么没有发生级联删除。

非常感谢您到目前为止的帮助。我已经到了这项工作的最后期限,所以如果我在周末没有解决它,我将不得不求助于执行 HQL 查询,因为我知道这对我有用:(

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);
    }

    public void updateCommunication(Communication comm) throws DataAccessException
    {       
        HibernateTemplate hibernate = getHibernateTemplate();
        Communication existing = (Communication)hibernate.get(Communication.class, comm.getComId());
        hibernate.initialize( existing.getCommunicationCountries());
        existing.getCommunicationCountries().clear();
        hibernate.saveOrUpdate(existing);       
    }

最佳答案

排名不分先后:

A) 假设您代码中的“myID”是您实体的标识符,您应该使用 session.get()而不是标准 - 它更快,而且绝对更容易:

MyObject obj = (MyObject) session.get(MyObject.class, new Long(1));

B) 如果您正在使用 Spring(通过 getHibernateTemplate() 调用判断),您应该始终如一地使用它 :-) 除非绝对必要,否则不要直接调用 session - 而且几乎永远不会必要的。以上get因此,方法将变为:

MyObject obj = (MyObject) getHibernateTemplate().get(MyObject.class, new Long(1));

如果您需要编写基于条件的查询,您可以使用 DetachedCriteriaHibernateTemplate.getByCriteria()方法:

DetachedCriteria crit = DetachedCriteria.forClass(MyObject.class)
 .add(Property.forName("myId").eq( new Long(1) ) );
List results = getHibernateTemplate().findByCriteria(crit);

C) 你通常不应该 evict()来自 session 的对象(无论如何在关闭之前立即执行它是毫无意义的)。你通常也不应该 close()您从 HibernateTemplate 获得的 session 。

D) 最后,就自动保存子项(一对多集合元素)而言 - 看看 this example它很好地解释了不同的级联设置。如果您仍然遇到问题,请发布您的映射/代码。

更新(基于问题的澄清):

1) 您的映射看起来不错,除了子类中父类的级联 (<many-to-one name="communication" cascade="all"/>)。您很可能不想要这个。

2) LazyInitializationException被抛出是因为 Hibernate 默认情况下将集合映射为惰性集合,这意味着子项(communicationCountries)在第一次访问之前不会加载。如果在 session 已经关闭时发生该访问,则会抛出异常。您可以通过调用 Hibernate.initialize() 来确保填充集合关于 Collection 。

3) 只要你在 Hibernate 返回的实体实例上调用它而不是你自己创建的实体实例(比如,从远程调用中解码),你的 delete() 应该可以正常工作,“communicationCountries”集合不是人口稠密。为了让 Hibernate 删除 child ,它需要知道他们存在。

4) 另一方面,您的 update() 是错误的。您正在加载一个实体,清除它的子实体,然后再次保存它——这本身很好——但这与传入的参数无关。

关于java - hibernate 级联删除不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1438678/

相关文章:

php - 无法从外部服务器运行 MySQL 查询

java - 访问 Lucene 4 中的术语统计信息

java - 配对游戏-setCard方法

python - postgres 插入规则而不是更新

sql - 如何将日期时间拼接成时间戳?

java - Spring @Transactional(Propagation.NEVER) 应该创建 Hibernate session 吗?

java - 具有抽象父类的 Hibernate 映射

java - Hibernate @Synchronize 似乎不起作用

Java Swing 为输出创建文本区域

java - MySQL/Hibernate SQLQuery 如何将 unsigned int(10) 转换为smallint?