休眠:更新对象 - >还执行了不需要的删除语句

时间:2010-12-15 17:09:40

标签: java hibernate

我在我的Java应用程序中使用Hibernate作为ORM。 我有一个项目< - > person manytomany-relation和Project是映射所有者。

现在我遇到了问题,我想要更新项目。该项目有一个id,一个名字,......和一组人。执行更新时,将在Project_Person连接表中删除所有人员,控制台上的SQL语句:

Hibernate: update Project set description=?, name=? where id=?
Hibernate: delete from Project_Person where project_id=?

但我不希望删除语句被执行。

我在Java应用程序中有这个:

this.projService.updateProject(p);

其中p是项目,但是在没有人员集合的POJO方式中。所以我想,为了使它成为“Hibernate-ready”,我在一个单独的事务中创建了一个findProjectById,所以我从数据库中获取项目:

Project proj = this.projService.findProjectById(p.getId());
proj.setName(p.getName());
proj.setDescription(p.getDescription());

所以我得到了Hibernate-ready Project对象,更改了值,然后告诉他更新项目。但是Set在调试器视图中是PersistentSet,并且没有人(我认为,因为它们是延迟加载的)。 但是用

更新
session.update(p);

在新事务中,我得到更新语句和不需要的删除语句。 如何避免删除语句?

我是否必须创建一个特殊的SQL语句,以便只更新我想要更新的数据库表字段?还是有其他/更好的解决方案?

最诚挚的问候。


更新 这会抛出一个LazyInitializationException:

public Project findProjectById(int projectId) {
    SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
    Session sess = sessionFactory.getCurrentSession();
    Transaction tx = sess.beginTransaction();
    try {
        Project project = (Project)sess.createQuery("from Project where id = "+projectId).list().get(0);
        tx.commit();
        System.out.println(project.getPersons().size());
        return project;
    } catch (IndexOutOfBoundsException ex) {
        return null;
    }
}

调试器的屏幕截图

http://img94.imageshack.us/img94/2020/screendebugger.png

的HibernateUtil

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
    // SessionFactory of Hibernate
    private static final SessionFactory sessionFactory;
    static {
        try {
            sessionFactory = new Configuration().configure("/hibernate.cfg.xml").buildSessionFactory();
        }
        catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed. " + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

tx.commit()

之前的屏幕截图

http://img808.imageshack.us/img808/9624/screendebugger2.png

3 个答案:

答案 0 :(得分:2)

这意味着(如您所示)您的收藏是空的。但这不是由于延迟加载 - 调试器允许您加载集合。也许它是空的另一个原因。通过显示collection.size()确认这一点。

问题的另一部分是级联。如果您已定义为级联delete-orphan,则将其删除,或确保该集合实际已填充。

答案 1 :(得分:0)

您不需要拨打“更新”。

以下代码:

Project proj = this.projService.findProjectById(p.getId());
proj.setName(p.getName());
proj.setDescription(p.getDescription());

然后不需要更新,因为proj引用是持久的,并且将保存对它的任何更改。这是hibernate和其他ORM的一个特性,称为透明持久性。

有关hibernates更新方法的详细信息,请参阅here

答案 2 :(得分:0)

如果在新事务中更新Project对象,则可能应该使用

将对象与新Session关联
session.merge(project)

可能检测到未初始化的PersistentSet,将其替换为新Session中的新PersistentSet,并确保不删除Set的条目。否则Hibernate可能无法处理Set,因为创建它的事务已经关闭并假定它是空的。