我在尝试在 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));
如果您需要编写基于条件的查询,您可以使用 DetachedCriteria和 HibernateTemplate.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/