JPA 2.0 @OneToOne.orphanRemove vs. UNIQE INDEX

Ebenius

Top Contributor
Liebes Lieblingsforum,

ich arbeite mich gerade in JPA (2.0) ein. Abbilden möchte ich Artikel (Item) mit diversen Attributen. Manche Artikel haben eine komplexe Herstellungsanleitung (Recipe).

Mein Schema würde ich ungefähr so gestalten:
Code:
Item                  Recipe
===================   ===================
id : NUMBER, PK       id : NUMBER, PK
// and more           parentItem : NUMBER, (*** erstmal ohne UNIQUE INDEX ***)
                      // and more

Wenn ich das in JPA mappe, dann sieht das vereinfacht so aus (setter und getter mit dazu denken):
Java:
@Entity
class Item {
  @Id Long id;
  @OneToOne(orphanRemoval = true, cascade = ALL, mappedBy = "parentItem")
  Recipe recipe;
}
Java:
@Entity
class Recipe {
  @Id Long id;
  @OneToOne(optional = false) Item parentItem;
}
Ich spiele mit EclipseLink 2.0.1.v20100213-r6600 gegen eine Derby-DB 10.5.3.0 (in einem GlassFish v3).

  1. Lade ich nun eine Instanz von [c]Item[/c] die kein Recipe hat, füge ein Recipe hinzu und mache dann das Item wieder persistent, wird das Recipe in der Datenbank korrekt angelegt.
  2. Lade ich eine Instanz von [c]Item[/c] die ein Recipe hat, setze das Recipe auf [c]null[/c] und mache dann das Item persistent, wird das Recipe korrekt aus der Datenbank gelöscht.
  3. Lade ich eine Instanz von [c]Item[/c] die ein Recipe hat, ersetze das Recipe durch eine neue Instanz und mache dann das Item persistent, wird das alte Recipe gelöscht und das neue hinzugefügt.
Genau so stelle ich mir das vor.

Jetzt setze ich einen Unique Index (alternativ ein Unique Constraint; verhält sich gleich) auf [c]Recipe.parentItem[/c]. Fall 1 und Fall 2 verhalten sich genauso. Fall 3 aber führt zu einem sehr hässlichen Fehler:
Code:
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLException: DERBY SQL error: SQLCODE: -1, SQLSTATE: XJ001, SQLERRMC: java.lang.NullPointerException^T^TXJ001.U
Error Code: -1
Call: INSERT INTO RECIPE (parentItem) VALUES (?)
        bind => [2]
Query: InsertObjectQuery([Entity Recipe] id=null, parentItem=4711)
        at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:333)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.processExceptionForCommError(DatabaseAccessor.java:1422)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:799)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeNoSelect(DatabaseAccessor.java:867)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.basicExecuteCall(DatabaseAccessor.java:587)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeCall(DatabaseAccessor.java:530)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeCall(AbstractSession.java:914)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:205)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.executeCall(DatasourceCallQueryMechanism.java:191)
        at org.eclipse.persistence.internal.queries.DatasourceCallQueryMechanism.insertObject(DatasourceCallQueryMechanism.java:334)
        at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:162)
        at org.eclipse.persistence.internal.queries.StatementQueryMechanism.insertObject(StatementQueryMechanism.java:177)
        at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.insertObjectForWrite(DatabaseQueryMechanism.java:461)
        at org.eclipse.persistence.queries.InsertObjectQuery.executeCommit(InsertObjectQuery.java:80)
        at org.eclipse.persistence.queries.InsertObjectQuery.executeCommitWithChangeSet(InsertObjectQuery.java:90)
        at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeWriteWithChangeSet(DatabaseQueryMechanism.java:286)
        at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58)
        at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:675)
        at org.eclipse.persistence.queries.DatabaseQuery.executeInUnitOfWork(DatabaseQuery.java:589)
        at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWorkObjectLevelModifyQuery(ObjectLevelModifyQuery.java:109)
        at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeInUnitOfWork(ObjectLevelModifyQuery.java:86)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2857)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1225)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1207)
        at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1167)
        at org.eclipse.persistence.internal.sessions.CommitManager.commitNewObjectsForClassWithChangeSet(CommitManager.java:197)
        at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsForClassWithChangeSet(CommitManager.java:164)
        at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:116)
        at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:3260)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1403)
        at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.commitToDatabase(RepeatableWriteUnitOfWork.java:547)
        at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithPreBuiltChangeSet(UnitOfWorkImpl.java:1549)
        at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWork.writeChanges(RepeatableWriteUnitOfWork.java:360)
        at org.eclipse.persistence.internal.jpa.EntityManagerImpl.flush(EntityManagerImpl.java:696)
        at com.sun.enterprise.container.common.impl.EntityManagerWrapper.flush(EntityManagerWrapper.java:407)
        ...
Caused by: java.sql.SQLException: DERBY SQL error: SQLCODE: -1, SQLSTATE: XJ001, SQLERRMC: java.lang.NullPointerException^T^TXJ001.U
        at org.apache.derby.client.am.SQLExceptionFactory40.getSQLException(Unknown Source)
        at org.apache.derby.client.am.SqlException.getSQLException(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.executeUpdate(Unknown Source)
        at com.sun.gjc.spi.base.PreparedStatementWrapper.executeUpdate(PreparedStatementWrapper.java:108)
        at org.eclipse.persistence.internal.databaseaccess.DatabaseAccessor.executeDirectNoSelect(DatabaseAccessor.java:792)
        ... 121 more
Caused by: org.apache.derby.client.am.SqlException: DERBY SQL error: SQLCODE: -1, SQLSTATE: XJ001, SQLERRMC: java.lang.NullPointerException^T^TXJ001.U
        at org.apache.derby.client.am.Statement.completeExecute(Unknown Source)
        at org.apache.derby.client.net.NetStatementReply.parseEXCSQLSTTreply(Unknown Source)
        at org.apache.derby.client.net.NetStatementReply.readExecute(Unknown Source)
        at org.apache.derby.client.net.StatementReply.readExecute(Unknown Source)
        at org.apache.derby.client.net.NetPreparedStatement.readExecute_(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.readExecute(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.flowExecute(Unknown Source)
        at org.apache.derby.client.am.PreparedStatement.executeUpdateX(Unknown Source)
        ... 124 more

Ohne Unique Index sieht das Log so aus:
Code:
INSERT INTO RECIPE (parentItem) VALUES (?)
        bind => [2]

DELETE FROM RECIPE WHERE (id = ?)
        bind => [1]
Ich mutmaße daher, es handelt sich hier um zwei Fehler. 1. EclipseLink müsste eigentlich zuerst DELETE und danach INSERT ausführen. 2. Die DerbyDB verhält sich seltsam und zeigt eine NullPointerException, anstatt ordnungsgemäß über eine Constraint-Violation zu schimpfen. Hab ich da recht? Kennt das jemand? Mache ich beim Mapping etwas falsch? Ist das ein Bug im EclipseLink? Oder in der DerbyDB? Oder im JDBC-Treiber? Hab ich [c]@OneToOne.orphanRemove[/c] falsch verstanden? Hilfe! :eek:

Ich danke schonmal für Hinweise…
Ebenius
 
Zuletzt bearbeitet:
G

Gelöschtes Mitglied 5909

Gast
Ich hab zwar orphanRemoval noch nicht benutzt / gebraucht, aber

Hast du mal das loglevel auf FINE (in der persistence.xml) gestellt und gekuckt was er macht?

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

Probiers mal mit EclipseLink 2.1.0, hab in nem anderen Thread gelesen, dass da wohl der ein oder andere Bug behoben wurde

Hast du mal eine andere Embedded DB (h2, hsql) ausprobiert und gekuckt ob das gleiche passiert?
 

Ebenius

Top Contributor
Hast du mal das loglevel auf FINE (in der persistence.xml) gestellt und gekuckt was er macht?
Jupp, die Delete- und Insert-Zeilen oben sind aus dem FINE-Log; hab nur Zeitstempel etc. entfernt. Nach dem Insert flog die Exception und dann noch die Fehler aus den Wiederholversuchen.

Probiers mal mit EclipseLink 2.1.0, hab in nem anderen Thread gelesen, dass da wohl der ein oder andere Bug behoben wurde
Mal sehen wie ich das dem GlassFish beibringen kann.

Hast du mal eine andere Embedded DB (h2, hsql) ausprobiert und gekuckt ob das gleiche passiert?
Hab ich nicht. Aber ich werd's mal gegen meinen Oracle-Server testen.

Vielen Dank!
Ebenius
 

Ebenius

Top Contributor
Hallo raiL,

ich hab's zwar nicht hinbekommen, aber gehe jetzt ohnehin einen anderen Weg. :) Mach Dir also nicht die Mühe.

Hatte halt gehofft, jemand kennt das Problem schon oder kann mir gleich sagen, dass ich was falsch mache. Danke für die Hilfe, in jedem Fall!

BTW: EclipseLink einfach auf 2.1 im GlassFish hochzuziehen, hab ich nicht probiert. Wahrscheinlich werd ich das Problem einfach ignorieren, bis GlassFish 3.1 EclipseLink 2.1 einfach mitbringt. :)

Ebenius
 

Ähnliche Java Themen


Oben