我遇到了同样的问题,我希望能够设置密钥但不使用所有这些延迟加载的东西。我发现hibernate非常脆弱,到处都是错误和神秘的幽灵类。到目前为止,它并没有简化我的生活。考虑一下:
模型(大体简化):
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;
}
测试用例(注意:所有 'enterTrade()' 所做的只是将交易粘贴在交易表中,并且
调整投资组合中的头寸大小,'undoTrade()' 只是恢复):
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");
这个测试应该有效吗?错误的!不可思议的是,投资组合中还有 25 股 GOOG 股票。
基本问题是 trade2 对象指向一个变得陈旧的投资组合对象。最后一个 undoTrade() 操作使用的投资组合仍然有 75 股 GOOG。请注意,Trade2 永远不会过时,因为仅对其执行了 persist()。但是当在 Portfolio 上执行 update() 时,会创建一个额外的副本,而不是更改原始对象(就像使用 'persist()' 所做的那样)。我很难理解为什么这种设计不会被认为是愚蠢和容易出错的。这是一个简单的例子。这不像我们在谈论并发访问问题或任何花哨的东西。哦,当我尝试刷新 trade2 时,得到完全令人困惑的 LazyInitializationException。
所以,我的解决方案是使用键,以便每次需要刷新都是明确的:
Trade {
...
@ManyToOne(targetEntity=Portofio.class)
@JoinColumn(referenceColumnName="id")
public Long portfolio_id;
}
或其他。虽然我在这里表达了很多挫败感,但我很想听到关于如何处理这些问题的诚实解释。谢谢。