I'm having the same problem and am wanting to be able to set up keys but not use all this lazy load stuff. I find hibernate to be so fragile with errors and mysterious ghost classes all over the place. So far it's not simplifying my life. Consider this:
model (grossly simplified):
Portfolio {
...
@OneToMany(cascade = {CascadeType.ALL}, fetch=FetchType.EAGER )
@MapKey(name="symbol")
public Map<String,Position> positions;
}
Position {
String symbol; int quantity;
}
Trade {
String symbol; int quantity; // price,etc
...
@ManyToOne() // looser coupling here.
public Portfolio portfolio;
}
test case (note: all 'enterTrade()' does is stick the trade in a trade table and
adjust the position size in the portfolio, 'undoTrade()' just reverts):
Trade trade1 = new Trade("GOOG", 25, portfolio);
Trade trade2 = new Trade("GOOG", 50, portfolio);
portfolio = portfolioDAO.enterTrade(trade1);
portfolio = portfolioDAO.enterTrade(trade2);
portfolio = portfolioSource.undoTrade(trade1, user);
portfolio = portfolioSource.undoTrade(trade2, user);
Assert.assertFalse(portfolio.getPositions().containsKey("GOOG"),
"after both trades net a position of zero");
This test should work right? WRONG! Mysteriously there are still 25 GOOG shares in the portfolio.
The basic problem is that the trade2 object points to a portfolio object that becomes stale. The last undoTrade() operations uses a portfolio that still has 75 shares of GOOG. Note that Trade2 is never stale because only persist() has been executed on it. But when update() is performed on Portfolio, an extra copy is created rather than changing the original object (as is done with 'persist()'). I'm having trouble understanding why that design would not be considered stupid and error prone. This is a simple example. It's not like we're talking about concurrent access issues or anything fancy. Oh, and when I try to refresh trade2, get LazyInitializationException which is completely baffling.
So, my solution is to use keys so that every need to refresh is explicit:
Trade {
...
@ManyToOne(targetEntity=Portofio.class)
@JoinColumn(referenceColumnName="id")
public Long portfolio_id;
}
Or whatever. While I'm expressing much frustration here, I would love to hear an honest explanation of how to deal with these problems. Thanks.