views:

517

answers:

1

Lets setup the question first.

What I have is >4 tables: Customer, Address, Order, OrderItems. Each are mapped using Hibernate Annotations and accessed through a Spring DAO/Services layer.

What I am trying to do is merge duplicate customers together. So all that really needs to happen is all orders and addresses associated with customer B, need to update their customer_id foreign key to point to customer A. Then customer B must have its disabled bit set.

Instead of sending these simple queries to our database, hibernate goes crazy and issues a ton of select then update queries. Particularly it selects all order items attached to an order (because this is defined EAGER, and this point is not changeable.). To get the selects before update to stop happening I tried adding the hibernate entity annotation on top of the regular javax.persistence.Entity like:

@org.hibernate.annotations.Entity(dynamicUpdate = true, selectBeforeUpdate = false, dynamicInsert = true)

this seemed to have no affect, except with simple queries where it only updated single items in a table.

I get the objects using the following hibernate criteria:

Criteria c1 = null; Criteria c2 = null; Criteria c = session.createCriteria(Customer.class); c.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

        if(resultLimit>0) c.setMaxResults(resultLimit);
        if(timeout>0) c.setTimeout(timeout);
        for(String filter: sqlFilters) {
            if(filter.indexOf("{alias}.customer_")!=-1) c.add(Restrictions.sqlRestriction(filter));
            else if(filter.indexOf("{alias}.address_")!=-1 && addrsAttached) {
             if(c1==null)
              c1 = c.createCriteria("addresses").setFetchMode("type", FetchMode.JOIN);
             c1.add(Restrictions.sqlRestriction(filter));
            } else if(filter.indexOf("{alias}.order_")!=-1 && ordersAttached) {
             if(c2==null)
              c2 = c.createCriteria("orders").setFetchMode("orderItems", FetchMode.SELECT);
             c2.add(Restrictions.sqlRestriction(filter));
            }
        }
        return (List<Customer>) c.list();

Then i move all of the address and order objects from customer B to customer A and run a

return (Customer) this.getHibernateTemplate().merge(customer);

on both customer objects. This ends up creating a ton of select statements that get all of the associated objects (i.e. OrderItems, Products, ProductType, ProductPricingTmpl, etc..)

I need to get these selects removed! If they were not there the query would look normal and be efficient! The Update outputted queries are perfect and dynamic.

Any ideas?

+2  A: 

The clue might be in your choice of merge() operation. From the Hibernate javadoc:

Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded.

So you're forcing Hibernate to load all of the data in before modifying it.

Try a different operation, such as update() :

Update the persistent instance with the identifier of the given detached instance.

No promises, though, Hibernate might decide it needs to load it in anyway. The dynamicUpdates=true config might actually make it worse, since it needs to know what's there to start before it can issue dynamic updates.

skaffman