When you use Hibernate, you do so via a session. It is well known that the session acts as a first level cache, but sometimes this can cause confusing behaviour. Let’s look at a simple example. Suppose I have Customer and Order objects. An order has a reference to the customer who made the order, and similarly, a customer has a set of orders.
Suppose I create a single customer with three associated orders as follows:
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Customer customer = new Customer(); customer.setForename("Hedley"); customer.setSurname("Proctor"); session.save(customer); Order order1 = new Order(); order1.setOrderTotal(29.99); order1.setCustomer(customer); Order order2 = new Order(); order2.setOrderTotal(8.99); order2.setCustomer(customer); Order order3 = new Order(); order3.setOrderTotal(15.99); order3.setCustomer(customer); session.save(order1); session.save(order2); session.save(order3); session.flush();
As you can see, I’ve called flush() on the session, so the data has been sent to the database. Now let’s write a query that will pick out this customer, and assert that they have three orders:
Criteria criteria = session.createCriteria(Customer.class); criteria.add(Restrictions.eq("forename","Hedley")); criteria.add(Restrictions.eq("surname","Proctor")); List results = criteria.list(); Customer customer1 = (Customer) results.get(0); assertEquals(customer1.getOrders().size(),3);
This assertion will fail! Why? Because this criteria query just returns the customer object that you already have, which is in the session. Despite the fact that in the database the orders table really does have the correct foreign keys to the customers, because Hibernate has flushed all of the objects to the database, it doesn’t think that the session is dirty, so will happily return the Customer object that is the in session. What should you do to prevent confusion like this? The answer suggested by Java Persistence with Hibernate is that when you have a bidirectional association you should always have a helper method to add items to it, that will set both sides of the association, so you will never get this discrepancy between the session objects and the contents of the database.
This article is part of a series on Hibernate. You might be interested in some of the others:
Hibernate query limitations and correlated sub-queries
Bespoke join conditions with Hibernate JoinFormula
Inheritance and polymorphism