Question

I am getting a strange problem with Hibernate and merge.

The structure of the classes in question is like this:

Project --> CaseWorkerA --|> CaseWorker --|> User

So basically I have a Project class, which contains a reference to a CaseWorkerA, which is a subclass of CaseWorker, which again is a subclass of User.

In code:

public class Project {
    [...]
    private CaseWorkerA caseWorkerA;

    @ManyToOne(fetch = FetchType.EAGER)
    @Cascade({ org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.PERSIST,
           org.hibernate.annotations.CascadeType.REFRESH, org.hibernate.annotations.CascadeType.MERGE })
    @JoinColumn(name = "CaseWorker_A")
    public CaseWorkerA getCaseWorkerA() {
        return caseWorkerA;
    }
}

Then we have the User-hierarchy:

public class User {
    [...]
}

public class CaseWorker extends User {
    private CaseWorkerStatus status;

    @Enumerated(EnumType.STRING)
    public CaseWorkerStatus getStatus() {
        return status;
    }
    [...]
}

public class CaseWorkerA extends CaseWorker {
    [...]
}

Then, there is a method in a Dao-class, for storing a project:

public class ProjectDao {
    [...]
    public Project saveUpdateProject(final Project project) {
        if (project.getId() == null) {
            getSession(false).save(project);
        } else {
            project = (Project) getSession(false).merge(project);
        }
        getHibernateTemplate().flush();
        return project;
    }
}

Now, the problem is as follows:

The Dao-method recieves a project that exists in the database. This project is connected to a CaseWorkerA, which has a status CaseWorkerStatus.ACTIVE (in both the database and in the incomming object). But after the merge, the status of the caseworker becomes null.

I really don't get how this is possible, since the value is the same in the database, as in the object to be stored, I would expect it to stay the same after the merge.

(There are no triggers in the database for this field..)

(I am going to try to change the dao-method to use saveOrUpdate instead, but even if this will fix the problem I would still very much like to know what caused it in the first place).

Update:

So I fiddled around with the debugger, and found the following: When I queried the session for the CaseWorker in question, it appeared with it's status-field set (actually, the object returned was exactly the one that was connected to the Project).

Doing a saveOrUpdate, and then a get, resulted in a CaseWorker with the status-field set. So it seems to be a problem with the merge method..

Was it helpful?

Solution

Managed to figure it out, it turned out that there was a second path from Project to User (lastChangedBy kind of thing), where someone had decided to put cascade for some strange reason. So when the person who last changed the project was a CaseWorker, then the lastChangedBy referenced it as a User, which doesn't know anything about the status, so it was stored a null.

Code:

public class Project {
    private User changedBy;

    @Cascade({ org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.PERSIST,
               org.hibernate.annotations.CascadeType.REFRESH, org.hibernate.annotations.CascadeType.MERGE })
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "changed_by")
    public User getChangedBy() {
        return this.changedBy;
    }
    [...]
}

The user that was set as changedBy was retrieved from the database like this:

public class UserDao {
    public User getUser(final String userName) {
        return (User) getSession(false).createQuery("from User u where u.loginName = :username").setParameter("username", userName).uniqueResult();
    }
}

Appearantly, even if the user one ends up retrieving is-a CaseWorker, the fields pertaining to a CaseWorker does not get retrieved..

Anyways, removed the uneccesary cascade, and it's all good :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top