Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] Updating a entry that is in a inheritance heirarchy

Stryon,
I didn't see Tom's mail or the fact that your rev# is from Mar 2009 - I would follow Tom's suggestion and try a later release before raising a bug#.
http://wiki.eclipse.org/EclipseLink/Source
   thank you
   /michael

Michael O'Brien wrote:
Stryon, Good analysis, a NPE or any sort is definitely not good, I would raise a bug and attach your patch as a diff if possible, we can CQ it and assign the bug. This will also allow the issue to be tracked.
   thank you
   /michael
stryon wrote:
I have been working on an application that uses eclipselink 1.1.0.r3634. One
of the things that I am trying to represent is a class hierarchy that is
represented in the database as a group of tables. There is one table for the top level element that holds all of the common fields and sub-tables that
hold all of the unique elements from the sub-classes. I have implemented
this with entity classes that look something like this:
@Entity @Inheritance(strategy=javax.persistence.InheritanceType.JOINED) @DiscriminatorColumn(name="CAR_TYPE") @Table(name="CAR_DEFINITION")
@Entity @Table(name="SPORTS_CARS") @DiscriminatorValue(value="S")
@Entity @Table(name="VANS") @DiscriminatorValue(value="V")
The code that call it looks like this:
EntityManager manager = getEntityManager(); manager.getTransaction().begin(); manager.persist(<entity object>); manager.getTransaction().commit(); This works most of the time but I ran into an odd issue when trying to do an up update that just affected the fields in one of the sub-classes (ex.
setCargoCapacity on a van).

This is the stack trace for the error:
javax.persistence.RollbackExpection: java.lang.NullPointerExcpetion at org.eclipse.persistence.internal.jpa.transaction.EntryTransactionImpl.commitInternal(EntryTransactionImpl.java:102) at org.eclipse.persistence.internal.jpa.transaction.EntryTransactionImpl.commit(EntryTransactionImpl.java:63) at cars.Updater.update(Updater.java:397)
Caused by java.lang.NullPointerExcpetion         at
org.eclipse.persistence.platform.database.OraclePlatform.buildCallWithReturning(OraclePlatform.java:201) at org.eclipse.persistence.internal.expressions.SQLModifyStatement.buildCall(SQLModifyStatement.java:65) at org.eclipse.persistence.descriptors.ClassDescriptor.buildCallFromStatement(ClassDescriptor.java:641) at org.eclipse.persistence.internal.queries.StatementQueryMechanism.setCallFromStatement(StatementQueryMechanism.java:373) at org.eclipse.persistence.internal.queries.StatementQueryMechanism.prepareUpdateObject(StatementQueryMechanism.java:347) at org.eclipse.persistence.internal.queries.ExpressionQueryMechanism.prepareUpdateObject(ExpressionQueryMechanism.java:1629) at org.eclipse.persistence.internal.queries.StatementQueryMechanism.updateObject(StatementQueryMechanism.java:424) at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.updateObjectForWriteWithChangeSet(DatabaseQueryMechanism.java:1135) at org.eclipse.persistence.queries.UpdateObjectQuery.executeCommitWithChangeSet(UpdateObjectQuery.java:84) at org.eclipse.persistence.internal.queries.DatabaseQueryMechanism.executeCommitWithChangeSet(DatabaseQueryMechanism.java:286) at org.eclipse.persistence.queries.WriteObjectQuery.executeDatabaseQuery(WriteObjectQuery.java:58) at org.eclipse.persistence.queries.DatabaseQuery.execute(DatabaseQuery.java:664) at org.eclipse.persistence.queries.DatabaseQuery.executeUnitOfWorkt(DatabaseQuery.java:583) at org.eclipse.persistence.queries.ObjectLevelModifyQuery.executeUnitOfWorkt(ObjectLevelModifyQuery.java:86) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.internalExecuteQuery(UnitOfWorkImpl.java:2697) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1181) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1165) at org.eclipse.persistence.internal.sessions.AbstractSession.executeQuery(AbstractSession.java:1125) at org.eclipse.persistence.internal.sessions.CommitManager.commitChangedObjectsForClassWithChangeSet(CommitManager.java:232) at org.eclipse.persistence.internal.sessions.CommitManager.commitAllObjectsWithChangeSet(CommitManager.java:108) at org.eclipse.persistence.internal.sessions.AbstractSession.writeAllObjectsWithChangeSet(AbstractSession.java:3175) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabase(UnitOfWorkImpl.java:1277) at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWorkImpl.commitToDatabase(RepeatableWriteUnitOfWorkImpl.java:468) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitToDatabaseWithChanges(UnitOfWorkImpl.java:1373) at org.eclipse.persistence.internal.sessions.RepeatableWriteUnitOfWorkImpl.commitRootUnitofWork(RepeatableWriteUnitOfWorkImpl.java:160) at org.eclipse.persistence.internal.sessions.UnitOfWorkImpl.commitAndResume(UnitOfWorkImpl.java:1038) at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.commitInternal(EntityTransactionImpl.java:84) ... 28 more
The issue was traced down to
org.eclipse.persistence.internal.expressions.SQLModifiedStatement.buildCall(AbstractSession session). What was happening was while eclipselink was building up the sql string it would come down to this method to build the update string for the CAR_DEFINITION table. When it looked at the fields that needed to change,
however, it saw that none of them were in the CAR_DEFINITION table.
Old Method: public DatabaseCall buildCal(AbstractSession session) { SQLCall sqlCall = buildCallWithoutReturning(session); if ((getReturnFields() == null) || (getReturnFields().isEmpty()) { return sqlCall; } else { return session.getPlatform().buildCallWithoutReturning(sqlCall,getReturnFields()); } }
This would return a null from the first buildCallWithoutReturning. Since
there were in fact fields that needed to be returned it would not
immediately return. It would instead pass the null sqlCall variable into the platform's buildCallWithoutReturning method which then chokes on it with a
Null Pointer Exception.
New Method: public DatabaseCall buildCal(AbstractSession session) { SQLCall sqlCall = buildCallWithoutReturning(session); // quickly return if the build call had nothing to build if (sqlCall == null) || ((getReturnFields() == null) || (getReturnFields().isEmpty()) { return sqlCall; } else { return session.getPlatform().buildCallWithoutReturning(sqlCall,getReturnFields()); } }

Without the change, it doesn't get to the point of making the SQL. With the
change it does a simple update statement on the sub-table (ex 'Update
SPORTS_CARS set color='red' where car_id='15' ').
The way that I tried to fix this was by simply checking the results returned from the first buildCallWithoutReturning call and returning immediately if
it was null. This seems to work with all of the tests that I have run
against it, but I am not familiar enough with eclipselink to know the
ramifications of returning null from this method. Is this actually even an issue or am I doing something wrong with the configuration that is causing
this problem?
Also, is this something that has been previously detected and fixed? While it is one thing to override a classpath with a patched file, I would rather
run with an official build.





Back to the top