Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fetching JPA @OneToMany collection returns empty

I am trying out some EJB3 in Action examples using Glassfish4 (EclipseLink) + JavaDB. So I have the below relationship

@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;
    }    
    ...        
}

Now when fetching an Item like

@Override
public List<Bid> getBidsForItem(long itemId) {
    Item item = em.find(Item.class, itemId); // em -> Entity manager
    return item.getBids();
}

the item.getBids() returns an empty list (size = 0, not null). What changes should be done to get Bids for the given Item?

EDIT:
After enabling query logging as suggested in the comments

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

I notice that Queries are listed for insert statements but NO query is listed corresponding to em.find(Item.class, itemId).

EDIT 2 (ANSWER):
The problem was in my addBids() stateless bean function to which I was passing an Item object. This meant the Item Object is never in persistent context. The right way is to

  1. pass the itemId
  2. find the Item entity with entity manager find() method. This ensures that the Item object is in persistence context.
  3. add bid object to item and item to bid
  4. call entity manager persist() on Bid.

Corrected addBids() method:

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;  
}  

Thanks to @Chris for pointing out.

like image 744
Kiran Mohan Avatar asked Nov 26 '13 18:11

Kiran Mohan


2 Answers

Try instantiating a ArrayList<Bid> and assigning it to the List<Bid> declaration.

  @OneToMany(mappedBy="item")
  protected List<Bid> bids = new ArrayList<Bid>();
like image 74
Kevin Bowersox Avatar answered Oct 22 '22 02:10

Kevin Bowersox


Try this :-

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;
}

}

Here you are freeing the client to make the relationship. Do the otherway round in Bid class also. But make sure you won't end up with infinite to and fro method calls. And its a good approach to provide an add and remove method. like :- public class Item{ private List<Bid> bids= new ArrayList<>(); public void addBid(Bid bid) { bid.setItem(this); this.bids.add(bids); } }

like image 1
Manu Avatar answered Oct 22 '22 02:10

Manu