我在Hibernate中尝试删除时遇到了问题。每当我尝试删除时,由于存在子记录而导致问题,因此无法删除父级。我想删除孩子和父母。这是我的父映射:
<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的新对象进行更新时,父级会更新,但是第二次添加任何现有子级。我似乎无法移除孩子。当我使用ID检索对象并修改它时,我收到一个错误告诉我org.hibernate.LazyInitializationException:无法初始化代理 - 拥有的会话已关闭。我怀疑这是因为在一个getHibernateTemplate()调用中我得到了对象,我将它保存在另一个中,这是两个不同的会话?
当我删除时,由于存在子项,我收到错误。我知道我只是做了一些非常愚蠢的事情,因为我不知道这一切是如何运作的。
以下是我的更新和删除方法,在这种情况下,更新/保存是在保存之前检索和修改。删除使用的新对象ID与我要删除的DB中的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);
}
更新 所以这是我的新方法,但仍然没有快乐。我认为我的问题与孩子没有被加载/初始化等有关。虽然删除了,但我不明白为什么没有发生级联删除。
非常感谢你们的帮助。我已经完成了这项工作的截止日期,如果我周末没有解决这个问题,我将不得不求助于执行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);
}
答案 0 :(得分:2)
没有特别的顺序:
A)假设代码中的“myID”是您实体的标识符,您应该使用session.get()代替条件 - 它更快,更明确更容易:
MyObject obj = (MyObject) session.get(MyObject.class, new Long(1));
B)如果您正在使用Spring(通过getHibernateTemplate()
调用判断),您应该始终如一地使用它:-)并且除非绝对必要,否则不要直接调用会话 - 而且它很漂亮从来没有必要。因此,上述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()
来自会话的对象(无论如何在关闭之前立即执行此操作)。您通常也不应close()
从HibernateTemplate获得的会话。
D)最后,就自动保存子项(一对多集合元素)而言 - 请查看this example,它可以很好地解释不同的级联设置。如果您仍然遇到问题,请发布您的映射/代码。
更新(根据问题解释):
1)除了子类(<many-to-one name="communication" cascade="all"/>
)中父级的级联外,您的映射看起来没问题。你很可能不想要这个。
2)抛出LazyInitializationException
因为Hibernate默认将集合映射为lazy,这意味着在第一次访问之前不会加载子(communicationCountries)。如果在会话已关闭时发生该访问,则抛出异常。您可以通过在集合上调用Hibernate.initialize()
来确保填充集合。
3)你的delete()应该可以正常工作,因为你在Hibernate返回的实体实例上调用它而不是你自己创建的实例(比如,从远程调用解组),其中“communicationCountries”集合不是填充。为了让Hibernate删除子项,它需要知道它们存在。
4)另一方面,你的更新()是错误的。你正在加载一个实体,清理它的子节点并再次保存它 - 这本身很好 - 但它与传入的参数没有关系。