cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dougan Stuart <d...@swarmbox.com>
Subject Re: Extended class issues
Date Fri, 05 Aug 2016 18:11:20 GMT
Your fix is working as expected for my original use case. Thanks for working on this!

Doug

> On Aug 5, 2016, at 6:47 AM, Savva Kolbachev <s.kolbachev@gmail.com> wrote:
> 
> I've created a JIRA ticket for the issue CAY-2097
> <https://issues.apache.org/jira/browse/CAY-2097> and provided a fix
> https://github.com/apache/cayenne/commit/697f38e5127852a144b13e7640787e
> 57ac3ebba1
> 
> It's a little different from your. It's similar to how we check for
> properties in case of flattened attributes DataDomainDBDiffBuilder.java#L95
> <https://github.com/apache/cayenne/blob/master/cayenne-server/src/main/java/org/apache/cayenne/access/DataDomainDBDiffBuilder.java#L95>
> 
> BTW, not sure that we should check it here. Perhaps, we should check it
> while filling currentPropertyDiff and currentArcDiff. Looks like in this
> case performance will be slightly better.
> 
> 2016-08-03 21:24 GMT+03:00 Savva Kolbachev <s.kolbachev@gmail.com>:
> 
>> Hi Dougan,
>> 
>> I'm able to reproduce the problem you provided. I'll come back to you
>> after some investigation.
>> 
>> 2016-07-29 2:47 GMT+03:00 Dougan Stuart <doug@swarmbox.com>:
>> 
>>> Sure, here’s the relevant parts:
>>> 
>>> <db-entity name="company" schema="public">
>>>        <db-attribute name="name" type="VARCHAR" length="50”/>
>>>        <db-attribute name="uuid" type="OTHER" isPrimaryKey="true"
>>> isMandatory="true" length="2147483647"/>
>>> </db-entity>
>>> <db-entity name="entity" schema="public”>
>>>        <db-attribute name="audit_uuid" type="OTHER" length="2147483647
>>> ”/>
>>>        <db-attribute name="reference" type="VARCHAR" length="30"/>
>>>        <db-attribute name="type" type="CHAR" isMandatory="true"
>>> length="1”/>
>>>        <db-attribute name="uuid" type="OTHER" isPrimaryKey="true"
>>> isMandatory="true" length="2147483647”/>
>>>        <db-attribute name="parent_entity_uuid" type="OTHER" length="
>>> 2147483647"/>
>>> </db-entity>
>>> 
>>> <obj-entity name="Company" superEntityName="Entity"
>>> className=“...data.models.Company”>
>>>        <qualifier><![CDATA[type = "C"]]></qualifier>
>>>        <obj-attribute name="name" type="java.lang.String"
>>> db-attribute-path="company.name”/>
>>> </obj-entity>
>>> <obj-entity name="Entity" abstract="true" className=“...data.models.Entity"
>>> dbEntityName="entity" superClassName=“...data.CayenneBaseDataObject">
>>>        <obj-attribute name="reference" type="java.lang.String"
>>> db-attribute-path="reference”/>
>>>        <obj-attribute name="type" type=“...data.util.EntityType"
>>> db-attribute-path="type”/>
>>> </obj-entity>
>>> 
>>> <db-relationship name="entity" source="company" target="entity"
>>> toMany="false”>
>>>        <db-attribute-pair source="uuid" target="uuid"/>
>>> </db-relationship>
>>> <db-relationship name="company" source="entity" target="company"
>>> toDependentPK="true" toMany="false">
>>>        <db-attribute-pair source="uuid" target="uuid"/>
>>> </db-relationship>
>>> <db-relationship name="parentEntity" source="entity" target="entity"
>>> toMany="false”>
>>>        <db-attribute-pair source="parent_entity_uuid" target="uuid”/>
>>> </db-relationship>
>>> <db-relationship name="subEntities" source="entity" target="entity"
>>> toMany="true”>
>>>        <db-attribute-pair source="uuid" target="parent_entity_uuid”/>
>>> </db-relationship>
>>> 
>>> <obj-relationship name="parentCompany" source="Company" target="Company"
>>> deleteRule="Nullify" db-relationship-path="parentEntity"/>
>>> <obj-relationship name="subCompanies" source="Company" target="Company"
>>> deleteRule="Deny" db-relationship-path="subEntities"/>
>>> 
>>> 
>>> I’ve created a fix for this issue in DataDomainDBDiffBuilder.appendForeignKeys
>>> on line 133 (within the nested loop):
>>> 
>>> String joinSourceName = join.getSourceName();
>>> if (dbDiff.get(joinSourceName) == null && dbEntity.getAttribute(joinSourceName)
>>> != null) {
>>>        dbDiff.put(joinSourceName, value);
>>> }
>>> 
>>> The only change is that I’m checking if the dbEntity actually has the
>>> attribute it’s trying to add from the join. If it doesn’t have the
>>> attribute, then it doesn’t make sense to put it on the dbDiff. In
>>> DataDomainUpdateBucket.updatedAttribtues (mentioned in my prior
>>> message), it expects everything in the dbDiff to be an attribute that
>>> exists on the dbEntity. The fix passed Cayenne’s tests and didn’t appear
to
>>> cause any side effects. Of course, this is all moot if I just botched the
>>> data map. Let me know what you think.
>>> 
>>> Thanks,
>>> Doug
>>> 
>>> 
>>> 
>>> 
>>> 
>>>> On Jul 28, 2016, at 3:47 AM, Andrus Adamchik <andrus@objectstyle.org>
>>> wrote:
>>>> 
>>>> Would you mind posting a relevant part of your DataMap XML?
>>>> 
>>>> Andrus
>>>> 
>>>>> On Jul 13, 2016, at 8:40 PM, Dougan Stuart <doug@swarmbox.com>
wrote:
>>>>> 
>>>>> 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
>>>>> 
>>>> 
>>> 
>>> 
>> 
>> 
>> --
>> Best Regards,
>> Savva Kolbachev
>> 
> 
> 
> 
> -- 
> Best Regards,
> Savva Kolbachev


Mime
View raw message