OneToMany关系不起作用

时间:2011-11-28 20:22:18

标签: java jpa entity one-to-many

我的表格:

产品: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}

如何解决这个问题?

5 个答案:

答案 0 :(得分:26)

错误消息。打印指令导致在底层IndirectSet上调用 toString()

  

TopLink会在实例变量中放置一个IndirectSet   包含域对象从数据库中读取。第一个   消息发送到IndirectSet,内容从中获取   数据库和正常的Set行为已恢复。

IndirectCollection类型是专门实现的,不在 toString()上实例化:

  

出于调试目的,#toString()不会触发数据库读取。

但是,对间接集合的任何其他调用,例如size()或isEmpty()都将实例化该对象。

  

数据库读取最终在其中一个“委托”时触发   方法首先调用getDelegate(),然后调用它   buildDelegate(),它将消息getValue()发送给值持有者。   值持有者执行数据库读取。第一个   消息发送到IndirectSet,内容从中获取   数据库和正常的Set行为已恢复。

另见IndirectList: not instantiated

答案 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;