2

I have a quite simple JAP-Entity without any links to other classes:

@Entity
@IdClass(TimestampNameAndGroupIdentity.class)
public class TechFitMainClassHistory extends JPABase {

    @Id
    @Basic
    protected Date timestamp;

    @Id
    @Basic
    protected String type_name;

    @Id
    @Basic
    protected String group_name;

    @Basic
    protected int count;

    ...

with IdClass:

public class TimestampNameAndGroupIdentity implements Serializable {
    private static final long serialVersionUID = 1L;

    public Date timestamp;
    public String type_name;
    public String group_name;

    ...

When in a test I try to merge it twice:

        em.merge(new TechFitMainClassHistory(date, "com.test.Main", "java", 2));
        em.merge(new TechFitMainClassHistory(date, "com.test.Main", "java", 2));

I get the following error

Caused by: org.apache.openjpa.lib.jdbc.ReportingSQLException: Violation of PRIMARY KEY constraint 'PK__TechFitM__D91CE761E4A3725C'. Cannot insert duplicate key in object 'dbo.TechFitMainClassHistory'. The duplicate key value is (PROCESS_TYPE_MAIN, 2015-09-03 00:00:00.0000000, com.ruxit.Main). {prepstmnt 261650860 INSERT INTO TechFitMainClassHistory (group_name, timestamp, type_name, count) VALUES (?, ?, ?, ?)} [code=2627, state=23000]
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:219)
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.wrap(LoggingConnectionDecorator.java:207)
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator.access$1200(LoggingConnectionDecorator.java:59)
    at org.apache.openjpa.lib.jdbc.LoggingConnectionDecorator$LoggingConnection$LoggingPreparedStatement.executeBatch(LoggingConnectionDecorator.java:1215)
    at org.apache.openjpa.lib.jdbc.DelegatingPreparedStatement.executeBatch(DelegatingPreparedStatement.java:250)
    at org.apache.openjpa.jdbc.kernel.JDBCStoreManager$CancelPreparedStatement.executeBatch(JDBCStoreManager.java:1810)
    at org.apache.openjpa.jdbc.kernel.BatchingPreparedStatementManagerImpl.executeBatch(BatchingPreparedStatementManagerImpl.java:364)
    at org.apache.openjpa.jdbc.kernel.BatchingPreparedStatementManagerImpl.flushBatch(BatchingPreparedStatementManagerImpl.java:189)
    ... 39 more

There are two cases where the error does not appear: * If I commit between the calls * If the object already exists before the calls

This is just the reduced test-case, the actual application does similar things and I would expect things to work based on the description of the merge() method.

So why do I get this error? I would expect merge to work multiple times or this is a bug/limitation in OpenJPA?

centic
  • 14,264
  • 6
  • 58
  • 113
  • as said, this is just the test-case, in the real app the creation of the objects is spread across different places. As far as I read the doc for merge() it should allow this. And it works if I commit in-between! – centic Sep 03 '15 at 09:11
  • 2
    I would say this is a bug. Can you try to run the test with another implementation like Hibernate or EclipseLink? – geert3 Sep 03 '15 at 10:30
  • This is a bug. You should open a JIRA for this issue. – Rick Sep 04 '15 at 14:43

1 Answers1

0

the expected behavior of merge is :

  • Find in persistence context an attached object with the same id.
  • If exists update and return the already attached object (and let the given one unmanaged).
  • If doesn't, make a copy, persist it (attach it) and return it (and let the given original instance unmanaged)...

So the behavior you expect in the test case should work unless both merge call are not made on the same persistence context (the fact that a commit between the tow call fix your error leads to think that it's the case)

However in a concurrent context you will reproduce this problem as both entity will belongs to two different and so isloated persistence context, the second one to flush will trigger a pk violation

Gab
  • 7,071
  • 2
  • 32
  • 62
  • The calls are done on the same ```EntityManager``` instance, so I would expect it uses the same persistence context internally, so you say this sounds like a bug in the JPA implementation? – centic Sep 03 '15 at 10:23
  • well maybe... but on their sites they say they successfully passed the compliance test (http://openjpa.apache.org/). - see also http://stackoverflow.com/a/12746806/2087640 - What if you keep a reference on the result of the 1st merge call ? – Gab Sep 03 '15 at 10:32
  • see also : http://techblog.bozho.net/how-does-merge-work-in-jpa-and-hibernate/ - Maybe openJPA does not make the check against persistence context for a transient instance but only against the database itself ? it would explain your case... strange behavior anyway I think you have to look at the sources – Gab Sep 03 '15 at 10:47