Tim
Tim

Reputation: 13258

Hibernate: Update an object -> also unwanted delete statements are performed

I am using Hibernate as an ORM in my Java application. I have a Project <-> Person manytomany-relation and the Project is the mapping owner.

Now I have the problem, that I want to update the Project. The Project has an id, a name, ... and a Set of Persons. Doing an update, the persons are all deleted in the Project_Person join table, the SQL statements on the console:

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

But I do not want that the delete-statement is executed.

I have this in my Java application:

this.projService.updateProject(p);

where p is the Project, but in a POJO way without the Set of Persons. So I thought, to make it "Hibernate-ready" I make this within a separate transaction a findProjectById, so I fetch the project from the database:

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

So I get the Hibernate-ready Project object, change the values and then tell him to update the project. But the Set is in the debugger view a PersistentSet and there are no Persons in it (I think, because they are lazy-loaded). But updating with a

session.update(p);

within a new transaction, I get the update statement, and the unwanted delete statement. How can I avoid the delete statement?

Do I have to create a special SQL statement so that only the database table fields which I want to update will be updated? Or are there other/better solutions?

Best Regards.


Update This throws a 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;
    }
}

Screenshot of the Debugger:

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

Screenshot before the tx.commit()

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

Upvotes: 2

Views: 2809

Answers (3)

Reboot
Reboot

Reputation: 1744

If you update the Project object in a new transaction you probably should associate the object with the new Session using

session.merge(project)

Maybe that detects the uninitialized PersistentSet, replaces it with a new one from the new Session and will make sure the entries of the Set are not deleted. Otherwise Hibernate maybe not be able to handle the Set since the transaction that created it is already closed and assumes that it is empty.

Upvotes: 0

Michael Wiles
Michael Wiles

Reputation: 21186

You do not need the call "update".

The following code:

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

Does not then need the update as the proj reference is persistent and any changes to it will be saved. This is a feature of hibernate and other ORM's known as transparent persistence.

see here for more information on hibernates update method.

Upvotes: 0

Bozho
Bozho

Reputation: 597076

This means (as you suggested) that your collection is empty. But it's not due to lazy-loading - the debugger would allow you to load the collection. Perhaps it is empty for another reason. Confirm this by showing collection.size().

The other part of the issue is the cascade. If you have defined to cascade delete-orphan, then either remove it, or make sure the collection is actually filled.

Upvotes: 2

Related Questions