我在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 代理(所有字段都为 null,包括 id 字段)。这是与
currentCustomer.lastItem
中相同的对象。 - 对象
lastOrder.items
元素上手动调用 GrailsHibernateUtils.unwrapIdProxy()
,以确保其中没有代理(这基本上会导致 EAGER 获取)。这一个代理对象会导致一些非常奇怪的异常,在测试阶段很难跟踪。
有趣的事实是:如果我改变操作的顺序(先加载订单,然后再加载客户),则
lastOrder.items
中的每个元素都会被初始化。问题是:是否有一种方法告诉 Hibernate 在访问集合时应初始化它们,而不管集合中是否已存在任何元素的代理?
it
是代理,则println "${it.id}"
不会触发初始化,您必须获取一个非ID属性。 - Ian Roberts