Question

This should be a trivially easy task, but I can't get it to work.

I want to be able to revert changes to a lazy-loaded collection (let's call it kittens) hanging off the main entity (let's call it Cat) which are maintained in a single Hibernate session.

The collection is defined as so (replacing my dull entities with cats and kittens):

@Entity
@Table(name="CAT")
public class Cat {

    private Map<Long, Kitten> kittens;

    @OneToMany(fetch=FetchType.LAZY, mappedBy="mother", cascade={CascadeType.ALL})
    @MapKey(name="id")
    public Map<Long, Kitten> getKittens() {
        return kittens;
    }

    ...
}

@Entity
@Table(name="KITTEN")
public class Kitten {

   private Cat mother;

    @ManyToOne(fetch=FetchType.LAZY, cascade={CascadeType.PERSIST, CadcadeType.MERGE)
    @JoinColumn(name="MOTHER_CAT_ID", nullable=false)
    public Cat getMother {
        return mother;
    }

    ...
}

Users are able add to and remove from the kittens collection to their heart's content without it being persisted until they explicitly save and a session flush is performed.

But if the user chooses to revert the original list of kittens should be retrieved again from the database.

I have tried to achieve this full reversion of the collection by evicting the kittens collection from the second-level cache and then re-getting the Cat entity from the database using the following pattern:

public class CatDao {

    public Cat reset(Cat cat) {

        SessionFactory sessionFactory = Util.getSessionFactory();
        sessionFactory.evictCollection(Cat.class.getName() + ".kittens", cat.getId());

        Cat original = (Cat)this.session.get(Cat.class, cat.getId());
        Hibernate.initialize(original.getKittens());

        return original;
    }

    ...
}

It doesn't re-retrieve the kittens from the database (as shown by logging). What am I doing wrong?

Was it helpful?

Solution

Evicting the kittens from the second level cache has no effect as long as they are still in the first level cache. That is where the objects are loaded from. And in the first level cache there are only the references, i. e. when you modify an instance and reload the entity from the first level cache, you get the modified instance again.

The first level cache is inside the session object. You have to evict the kittens from the session using Session.evict(). (Session.clear() or creating a new session has the same effect, but will force a reload of all objects stored in the first level cache of the session. It depends of your application if this is the better solution.)

After this modification I think, you don't need to call SessionFactory.evictCollection() at any moment. By the way, SessionFactory.evictCollection() is marked as deprecated.

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