Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

@ElementCollection with Map<Entity, Embeddable> where Entity is a field of the Embeddable

After searching through the JPA docs and various posts, I'm confused as to whether the following is possible with JPA2.0. I'm just starting out with JPA so excuse me if I'm doing something stupid,

My domain model has a "Portfolio", which contains zero or more "open positions". A position consists of an "Instrument" (which is a JPA Entity) and a price (double). The portfolio is as follows:

@Entity (name = "portfolio")
public class Portfolio {
    @Id
    @Column (name = "id")
    @GeneratedValue
    private long id;

    @ElementCollection (fetch = FetchType.EAGER)
    @CollectionTable (name = "portfolio_entry", joinColumns = @JoinColumn (name = "portfolio_id"))
    private final Map<Instrument, OpenPosition> positions = new HashMap<Instrument, OpenPosition>();
....

The OpenPosition Embeddable is as follows:

@Embeddable
public class OpenPosition extends Position {
    @ManyToOne (targetEntity = InstrumentImpl.class, optional = false)
    @JoinColumn (name = "instrument_id", nullable = false)
    protected Instrument instrument;

    @Column (name = "price", nullable = false)
    protected double price;
....

and the Instrument entity is:

@Entity (name="instrument")
public class Instrument {
    @Id
    @Column(name = "id")
    @GeneratedValue
    private long id;

    @Column(name = "isin", nullable = false)
    private String isin;
....    
    @Override 
    public int hashCode() {
        int hash = 17;
        hash = 31 * hash + isin.hashCode();
    ....

When I try to use this, the schema is created and I am able to persist portfolios, but when trying to retrieve them, I get a NullPointerException in the hashCode method of the Instrument class. It seems JPA is trying to get the hash code to build the Map key, but the Instrument object has not been loaded.

I can see through debugging that although the id is set in the Instrument object, all the other fields are null.

So my question is, does JPA2.0 allow an ElementCollection where the key is an Entity that is also present as a field of the Embeddable value? If so, what am I screwing up. And if not, is the best workaround to use the id of the Instrument entity as the key instead?

Thanks in advance.

p.s. I'm using the hibernate 4.1.4 JPA implementation.

like image 421
hendalst Avatar asked Oct 06 '22 22:10

hendalst


1 Answers

So my question is, does JPA2.0 allow an ElementCollection where the key is an Entity that is also present as a field of the Embeddable value?

Yes, i managed to do it with this mapping:

@ElementCollection( targetClass = FreightBid.class )
@MapKeyJoinColumn( name = "carrier_id", referencedColumnName = "id" )
@CollectionTable( name = "freight_bid",
    joinColumns = @JoinColumn( name = "offer_pool_id" ) )
@Access( AccessType.FIELD )
private Map<Carrier,FreightBid> bidsByCarrier;

In my case, Carrier is an @Entity and FreightBid is an @Embedded

I've been able to persist and retrieve the Entity that contains this map correctly.

what am I screwing up.

You should remove the field protected Instrument instrument; from OpenPosition class and instead use the annotation @MapKeyJoinColumn on the map field in Portfolio class to declare wich column should be used as join column to the map key.

Also it would be best to avoid using other fields than id in the hashCode method of an object wich act as a map key... you JPA implementor might screw things up.

like image 66
Lucas Oliveira Avatar answered Oct 10 '22 03:10

Lucas Oliveira