OneToMany关系无效
我的表:
产品 :id,名称
优惠 :id,value,product_id
实体:
@Entity @Table(name="product") public class Product implements Serializable { @OneToMany(mappedBy="product") private Set offers; ... } @Entity @Table(name="offer") public class Offer implements Serializable { @ManyToOne @JoinColumn(name="PRODUCT_ID") private Product product; ... }
当我尝试从表Product
获取一些数据时,我得到一个java.lang.NullPointerException
,这段代码: product.getOffers()
返回:
{IndirectSet:未实例化}
如何解决这个问题?
这不是错误消息。 print指令导致在底层IndirectSet上调用toString() 。
当从数据库中读取包含域对象时,TopLink将在实例变量中放置IndirectSet。 将第一条消息发送到IndirectSet后,将从数据库中提取内容并恢复正常的Set行为。
IndirectCollection类型具体实现为不实例化toString() :
出于调试目的,#toString()不会触发数据库读取。
但是,对间接集合的任何其他调用(例如size()或isEmpty())都将实例化该对象。
当一个“委托”方法首次调用getDelegate()时,最终会触发数据库读取,而getDelegate()又调用buildDelegate(),它将消息getValue()发送给值持有者。 值持有者执行数据库读取。 将第一条消息发送到IndirectSet后,将从数据库中提取内容并恢复正常的Set行为。
另请参见IndirectList:未实例化
如果您在访问product.getOffers()
时获得{IndirectSet: not instantiated}
,那么您很可能在事务之外执行此代码。
默认情况下, @OneToMany
和@ManyToMany
关系是延迟加载的 ,这意味着,为了获得更好的性能,只有当您第一次访问数据时,才会获取数据。 这必须在活动事务中发生。
如果您不在此范围内访问此数据,则无法再访问此数据。 您应该将调用代码放在活动事务中,或者将集合更改为渴望而不是延迟:
@OneToMany(mappedBy="product", fetch=FetchType.EAGER)
这就是我做的
// force load of the set. entity.getSecrets().isEmpty(); System.out.println(entity.getSecrets());
这解决了我的问题
@OneToMany(mappedBy =“columnName”,cascade = {CascadeType.ALL},fetch = FetchType.EAGER)