[
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.