我的表格:
产品:id,name
优惠:id,value,product_id
实体:
@Entity
@Table(name="product")
public class Product implements Serializable {
@OneToMany(mappedBy="product")
private Set<Offer> 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:not instantiated}
如何解决这个问题?
答案 0 :(得分:26)
此不错误消息。打印指令导致在底层IndirectSet上调用 toString()。
TopLink会在实例变量中放置一个IndirectSet 包含域对象从数据库中读取。第一个 消息发送到IndirectSet,内容从中获取 数据库和正常的Set行为已恢复。
IndirectCollection类型是专门实现的,不在 toString()上实例化:
出于调试目的,#toString()不会触发数据库读取。
但是,对间接集合的任何其他调用,例如size()或isEmpty()都将实例化该对象。
数据库读取最终在其中一个“委托”时触发 方法首先调用getDelegate(),然后调用它 buildDelegate(),它将消息getValue()发送给值持有者。 值持有者执行数据库读取。第一个 消息发送到IndirectSet,内容从中获取 数据库和正常的Set行为已恢复。
答案 1 :(得分:13)
如果您在访问{IndirectSet: not instantiated}
时获得product.getOffers()
,那么您可能会在事务之外执行此代码。
默认情况下,@OneToMany
和@ManyToMany
关系为lazy loaded,这意味着,为了获得更好的性能,只有在您第一次访问数据时,才能获取数据。这必须在活动交易中发生
如果您不在此范围内访问此数据,则无法再访问此数据。您应该将调用代码放在活动事务中,或者将集合更改为eager而不是延迟:
@OneToMany(mappedBy="product", fetch=FetchType.EAGER)
答案 2 :(得分:6)
这就是我做的事情
// force load of the set.
entity.getSecrets().isEmpty();
System.out.println(entity.getSecrets());
答案 3 :(得分:0)
这解决了我的问题
@OneToMany(mappedBy =“columnName”,cascade = {CascadeType.ALL},fetch = FetchType.EAGER)
答案 4 :(得分:0)
我将Eclipselink 2.5.2版本用作ORM供应商,并且在延迟加载包含实体的同时,在一对多JPA映射中遇到了这个问题。对我有用的解决方法是:-
final List<ContainingEntity> list = Collections.unmodifiableList(new ArrayList<>
(containerEntity.getContainingEntityList());
“容器实体”侧的映射为:
@OneToMany(mappedBy = containerEntity, cascade = CascadeType.ALL, fetchType = FetchType.LAZY)
private List<ContainingEntity> containingEntityList;
从包含实体一侧映射为:
@ManyToOne
@JoinColumn(name = "container_entity_id")
private ContainerEntity containerEntity;