I have a class Company with a one-to-many relationship to other Companies
(parentCompany <- subCompanies). I’m able to set a Company’s parent when
creating one, but upon update I’m getting a NullPointerException in
DefaultQuotingStrategy.quotedName because it’s been sent a null attribute.
Company extends the abstract class Entity; on the DB side Entity and Company
have a one-to-one relationship, and Entity has a parentEntity reference (which
is modeled as parentCompany). The obj-relationship parentCompany is set up with
the target Company and path parentEntity.
The null attribute is being added in
org.apache.cayenne.access.DataDomainUpdateBucket.updatedAttributes. The method
is called first with the dbEntity Entity and the an updatedSnapshot containing
parentEntity, which is what I would expect. However, after this
updatedAttributes is called with Company and an updatedSnapshot containing
parentEntity, so the following line
attributes.add(entityAttributes.get(name))
will return a null attribute when trying to get the name “parentEntity” off
Company’s attributes; that attribute only exists on Entity. I’d appreciate any
help on preventing it from trying to add invalid attributes.
I’m not sure if this is the root cause, but
DataDomainUpdateBucket.appendQueriesInternal calls updatedAttributes based off
the bucket’s dbEntities, which in this case are set in
DataDomainSyncBucket.groupObjEntitiesBySpannedDbEntities; this method is only
adding Company as a “secondary DbEntity” (as referred to in the comments)
because Company has a flattened attribute “name" that does not exist on the
Entity.
Here’s the stack trace:
java.lang.NullPointerException
at
org.apache.cayenne.dba.DefaultQuotingStrategy.quotedName(DefaultQuotingStrategy.java:62)
at
org.apache.cayenne.access.translator.batch.UpdateBatchTranslator.createSql(UpdateBatchTranslator.java:60)
at
org.apache.cayenne.access.translator.batch.DefaultBatchTranslator.ensureTranslated(DefaultBatchTranslator.java:52)
at
org.apache.cayenne.access.translator.batch.DefaultBatchTranslator.getSql(DefaultBatchTranslator.java:64)
at
org.apache.cayenne.access.jdbc.BatchAction.runAsBatch(BatchAction.java:103)
at
org.apache.cayenne.access.jdbc.BatchAction.performAction(BatchAction.java:90)
at
org.apache.cayenne.access.DataNodeQueryAction.runQuery(DataNodeQueryAction.java:97)
at org.apache.cayenne.access.DataNode.performQueries(DataNode.java:293)
at
org.apache.cayenne.access.DataDomainFlushAction.runQueries(DataDomainFlushAction.java:233)
at
org.apache.cayenne.access.DataDomainFlushAction.flush(DataDomainFlushAction.java:154)
at org.apache.cayenne.access.DataDomain.onSyncFlush(DataDomain.java:693)
at org.apache.cayenne.access.DataDomain$2.transform(DataDomain.java:659)
at
org.apache.cayenne.access.DataDomain.runInTransaction(DataDomain.java:720)
at
org.apache.cayenne.access.DataDomain.onSyncNoFilters(DataDomain.java:655)
at
org.apache.cayenne.access.DataDomain$DataDomainSyncFilterChain.onSync(DataDomain.java:863)
at org.apache.cayenne.access.DataDomain.onSync(DataDomain.java:636)
at
org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:727)
at
org.apache.cayenne.access.DataContext.commitChanges(DataContext.java:676)
Thanks,
Doug