获取 JPA @OneToMany 集合返回空集

6

我正在尝试使用Glassfish4(EclipseLink)+ JavaDB来实践一些EJB3实战例子。因此,我有以下关系

@Entity
@Table(name = "ITEMS")
public class Item implements Serializable {
    private static final long serialVersionUID = 1L;

    private Long itemId;
    ...
    private List<Bid> bids= new ArrayList<>();

    @Id
    @Column(name="ITEM_ID")
    public Long getItemId() {
        return itemId;
    }

    public void setItemId(Long itemId) {
        this.itemId = itemId;
    }

    @OneToMany(mappedBy="item",fetch=FetchType.EAGER)   
    @JoinColumn(name="BID_ITEM_ID",referencedColumnName="ITEM_ID")
    public List<Bid> getBids() {
        return bids;
    }

    public void setBids(List<Bid> bids) {
        this.bids = bids;
    }   
}

@Entity
@Table(name="BIDS")
public class Bid implements Serializable{
    private static final long serialVersionUID = 1L;

    ...   
    private Item item;    
    ...

    @Id
    @Column(name="BID_ID")
    public Long getBidId() {
        return bidId;
    }

    public void setBidId(Long bidId) {
        this.bidId = bidId;
    }

    @ManyToOne
    @JoinColumn(name="BID_ITEM_ID",referencedColumnName="ITEM_ID")
    public Item getItem() {
        return item;
    }

    public void setItem(Item item) {
        this.item = item;
    }    
    ...        
}

现在当获取类似于 Item 的内容时,
@Override
public List<Bid> getBidsForItem(long itemId) {
    Item item = em.find(Item.class, itemId); // em -> Entity manager
    return item.getBids();
}

item.getBids()返回一个空列表(大小为0,非null)。如何更改才能获取给定商品的竞标?

编辑:
如评论所建议,启用查询日志记录后。

<property name="eclipselink.logging.level.sql" value="FINE"/>
<property name="eclipselink.logging.parameters" value="true"/>

我注意到插入语句的查询被列出,但是没有对应于em.find(Item.class, itemId)的查询被列出。
编辑2(答案): 问题出在我的addBids()无状态bean函数上,我向其中传递了一个Item对象。这意味着Item对象从未处于持久化上下文中。正确的方法是
1. 传递itemId 2. 使用实体管理器的find()方法找到Item实体。这确保了Item对象处于持久化上下文中。 3. 将竞价对象添加到项目中并将项目添加到竞价中 4. 在Bid上调用实体管理器persist()
修正后的addBids()方法:
public Bid addBids(Date bidDate, Double bidPrice, long itemId, String bidder) {  
        Item item = em.find(Item.class, itemId);  
        Bid bid = new Bid(bidDate, bidPrice, item, bidder);  
        item.getBids().add(bid);  
        em.persist(bid);  
        return bid;  
}  

感谢@Chris的指出。

数据库中是否包含适当的数据? - Kevin Bowersox
@Kevin Bowersox - 是的。假设具有ITEM_ID = 100的物品有两个出价,其BID_ID为(5000、5001),且BID_ITEM_ID = 100。 - Kiran Mohan
2
为什么不观察已执行的SQL查询语句呢(可以在EclipseLink中查找如何启用查询日志记录)?你确定使用了正确的数据库吗? - V G
4
通过调用em.refresh(item)来刷新该项。如果它有投标,请确保您维护双向关系的两个方面。每次将项目添加到投标中时,必须将投标添加到该项目的投标列表中。 - Chris
@KiranMohan 像这里所描述的那样执行(将出价添加到物品列表中并将物品设置为出价):https://dev59.com/1XnZa4cB1Zd3GeqPo1nK#20093000 - V G
显示剩余2条评论
2个回答

1
尝试实例化一个 ArrayList<Bid> 并将其分配给 List<Bid> 声明。
  @OneToMany(mappedBy="item")
  protected List<Bid> bids = new ArrayList<Bid>();

这是以这种方式完成的。请注意,结果列表大小为0且列表引用不为空。如果不分配ArrayList,则会出现空指针异常。 - Kiran Mohan
@KiranMohan 您的映射看起来正确,也许可以发布整个实体? - Kevin Bowersox

1
尝试这个:-
public class Item{
private List<Bid> bids= new ArrayList<>();
public void setBids(List<Bid> bids) {
    for (Bid bid : bids) {
        bid.setItem(this);
    }
    this.bids = bids;
}

}

在这里,您让客户端自由地建立关系。在Bid类中也要反过来做。但要确保不会出现无限的方法调用。 提供添加和删除方法是一个好方法。 例如:- public class Item{ private List<Bid> bids= new ArrayList<>(); public void addBid(Bid bid) { bid.setItem(this); this.bids.add(bids); } }


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接