我在使用 Grails 中的代理对象时遇到了困难。假设我有以下
class Order {
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name="xxx", joinColumns = {@JoinColumn(name = "xxx")}, inverseJoinColumns = {@JoinColumn(name = "yyy")})
@OrderBy("id")
@Fetch(FetchMode.SUBSELECT)
private List<OrderItem> items;
}
class Customer {
@ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = true)
@JoinColumn(name = "xxx",insertable = false, nullable = false)
private OrderItem lastItem;
private Long lastOrderId;
}
在一些控制器类里面
//this all happens during one hibernate session.
def currentCustomer = Customer.findById(id)
//at this point currentCustomer.lastItem is a javassist proxy
def lastOrder = Order.findById(current.lastOrderId)
//lastOrder.items is a proxy
//Some sample actions to initialise collections
lastOrder.items.each { println "${it.id}"}
迭代后lastOrder.items
仍包含 的代理currentCustomer.lastItem
。例如,如果 lastOrder.items 集合中有 4 个项目,它看起来像这样:
- 目的
- 目的
- javassist 代理(所有字段为空,包括 id 字段)。这与 currentCustomer.lastItem 中的对象相同。
- 目的
此外,这个代理对象的所有属性都设置为 null,并且在调用 getter 时它没有被初始化。我必须手动调用GrailsHibernateUtils.unwrapIdProxy()
内部的每个元素lastOrder.items
以确保内部没有代理(这基本上会导致 EAGER 获取)。
这个代理对象会导致一些非常奇怪的异常,这些异常在测试阶段很难跟踪。
有趣的事实:如果我改变操作的顺序(首先加载订单,然后加载客户),里面的每个元素都会lastOrder.items
被初始化。
问题是:有没有办法告诉 Hibernate 当它们被触摸时它应该初始化集合,不管集合中的任何元素是否已经在会话中被代理?