Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate: just save an entity with @EmbeddedId as primary key

I wanted to learn hibernate basics and do not understand why my application does not work, when adding an entry to my table using the @EmbeddedId annontations for composited primary keys:

Class representing the PK:

@Embeddable
public class OHLCVKey implements Serializable{

    private static final long serialVersionUID = -3996067621138883817L;

    @Column(name="Symbol")
    protected String symbol;

    @Column(name="Currency")
    protected String currency;

    @Column(name="Datum")
    protected java.sql.Date datum;

    public OHLCVKey() {}

    public OHLCVKey(String symbol, String currency, Date datum) {
        super();
        this.symbol = symbol;
        this.currency = currency;
        this.datum = datum;
    }



    public String getSymbol() {
        return symbol;
    }

    public void setSymbol(String symbol) {
        this.symbol = symbol;
    }

    public String getCurrency() {
        return currency;
    }

    public void setCurrency(String currency) {
        this.currency = currency;
    }

    public java.sql.Date getDatum() {
        return datum;
    }

    public void setDatum(java.sql.Date endTime) {
        this.datum = endTime;
    }

    @Override
    public String toString() {
        return String.format("OHLCKey: {%s %s %s}", symbol, currency, datum);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + (symbol == null ? 0 : symbol.hashCode());
        result = prime * result + (currency == null ? 0 : currency.hashCode());
        result = prime * result + (datum == null ? 0 : datum.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if(obj != null || !(obj instanceof OHLCVKey)) {
            OHLCVKey other = (OHLCVKey) obj;
            boolean sameSymbol = this.symbol.equals(other.symbol);
            boolean sameCurrency = this.currency.equals(other.currency);
            boolean endTime = this.datum.equals(other.datum);
            return sameSymbol && sameCurrency && endTime;
        }
        return false;
    }
}

Persistent class:

@Entity
@Table(name = "ohlcv_data")
public class OHLCV implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = -742762046516249869L;

    @EmbeddedId
    protected OHLCVKey key;

    @Column(name = "Exchange")
    private String exchange;

    @Column(name = "Open")
    private double open;

    @Column(name = "High")
    private double high;

    @Column(name = "Low")
    private double low;

    @Column(name = "Close")
    private double close;

    @Column(name = "Volume")
    private long volume;

    public OHLCV() {};

    public OHLCV(OHLCVKey key) {
        super();
        this.key = key;
    }

    public OHLCV(OHLCVKey key, String exchange, double open, double high, double low, double close, long volume) {
        super();
        this.key = key;
        this.exchange = exchange;
        this.open = open;
        this.high = high;
        this.low = low;
        this.close = close;
        this.volume = volume;
    }

    public OHLCVKey getKey() {
        return key;
    }

    public void setKey(OHLCVKey key) {
        this.key = key;
    }

    public String getExchange() {
        return exchange;
    }

    public void setExchange(String exchange) {
        this.exchange = exchange;
    }

    public double getOpen() {
        return open;
    }

    public void setOpen(double open) {
        this.open = open;
    }

    public double getHigh() {
        return high;
    }

    public void setHigh(double high) {
        this.high = high;
    }

    public double getLow() {
        return low;
    }

    public void setLow(double low) {
        this.low = low;
    }

    public double getClose() {
        return close;
    }

    public void setClose(double close) {
        this.close = close;
    }

    public long getVolume() {
        return volume;
    }

    public void setVolume(long volume) {
        this.volume = volume;
    }
}

I assumed that after creating an OHLC instance I could add it's data to my database table with the following function (in a class called OHLCVDataManager):

public void addOHLCV(OHLCV ohlcv) { // line 50
    Session session = factory.openSession();
    Transaction tx = null;
    try {
        tx = session.beginTransaction();
        session.save(ohlcv); // line 55
        tx.commit();
        log.info("Added {} to database!", key.toString());
    } catch(Exception e) {
        if(tx != null) {
            tx.rollback();
        }
        e.printStackTrace();
    } finally {
        session.close();
        System.exit(2); //TODO remove, exit Spring application
    }
}

But I got the following PropertyAccessException/IllegalArgumentException with stack traces:

org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [protected OHLCVKey OHLCV.key] by reflection for persistent property [OHLCV#key] : OHLCV@46479254
2018-11-03 18:43:57.567  INFO 18384 --- [       Thread-9] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@7582b66f: startup date [Sat Nov 03 18:43:53 CET 2018]; root of context hierarchy
    at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:75)
    at org.hibernate.tuple.entity.AbstractEntityTuplizer.getIdentifier(AbstractEntityTuplizer.java:224)
    at org.hibernate.persister.entity.AbstractEntityPersister.getIdentifier(AbstractEntityPersister.java:4931)
    at org.hibernate.mapping.Component$StandardGenerationContextLocator.locateGenerationContext(Component.java:480)
    at org.hibernate.id.CompositeNestedGeneratedValueGenerator.generate(CompositeNestedGeneratedValueGenerator.java:93)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:123)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:192)
    at org.hibernate.event.internal.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:38)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:177)
    at org.hibernate.event.internal.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:32)
    at org.hibernate.event.internal.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:73)
    at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:709)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:701)
    at org.hibernate.internal.SessionImpl.save(SessionImpl.java:696)
    at OHLCVDataManager.addOHLCV(OHLCVDataManager.java:55)
    at OHLCVDataManager.addOHLCV(OHLCVDataManager.java:70)
    at ServerApplication.main(ServerApplication.java:16)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49)
Caused by: java.lang.IllegalArgumentException: Can not set OHLCVKey field OHLCV
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
    at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
    at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
    at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
    at java.lang.reflect.Field.get(Field.java:393)
    at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:71)

EDIT1:

ohlcvDataManager.addOHLCV("TEST", "USD", new java.sql.Date(2018, 1, 1), "TEST", 1, 1, 1, 1, 1);

// OHLCDataManager#addOHLCV call:    
public void addOHLCV(String symbol, String currency, java.sql.Date date, 
String exchange, double open, double high, double low, double close, long volume) {
    addOHLCV(new OHLCV(new OHLCVKey(symbol,currency, date),exchange, open, high, low, close, volume));
}

EDIT2: I have testet hibernate-core version 5.3.7 and 5.4 with java 1.8

EDIT2: There is just one OHLCV class and one OHLCVKey class in my classpath, I have also tried to rename the classes.

like image 265
team17 Avatar asked Nov 03 '18 18:11

team17


People also ask

How do you make a foreign key a primary key in Hibernate?

You can use JPA's @MapsId annotation to tell Hibernate that it shall use the foreign key of an associated entity as the primary key. Let's take a look at a simple example. Each Book has a Manuscript, and each Manuscript belongs to 1 Book. The foreign key of the Book is also the primary key of the Manuscript.

Can we create entity in Hibernate without primary key?

No, Hibernate will not work without primary key. Every table should have some unique key.

What is @EmbeddedId in Hibernate?

The @EmbeddedId is used to instruct Hibernate that the Employee entity uses a compound key.

Can we update primary key in Hibernate?

No. Hibernate doesn't allow to change the primary key. In general, a primary key value should never change, if needs to be changed than the primary key column(s) are not good candidate(s) for a primary key.


2 Answers

I think you are hitting a bug with composite keys mapped as EmbededID in hibernate 5.0 and 5.1 It is supposed to be fixed in 5.1.1 https://hibernate.atlassian.net/browse/HHH-10618

Try changing the hibernate version. Also I can see in one of the comments that @K.Nicholas is saying that the same code works for him. This is why I am even more inclined to think you are hitting this bug.

like image 98
Alexander Petrov Avatar answered Oct 20 '22 12:10

Alexander Petrov


Downgrading to version

4.3.11.Final

worked...

like image 42
team17 Avatar answered Oct 20 '22 13:10

team17