You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@cayenne.apache.org by Andrew Willerding <aw...@itsurcom.com> on 2017/09/18 15:30:46 UTC

Question on how to properly create parent-child nested dependent objects?

Hi,

I am trying to create a DB record where a dependency record may not yet 
exist and I'm getting a "No rows for ..." error.  I don't understand how 
I should create the child record that will be used for the parent object 
so it can be referenced by the parent object without getting an error.  
The idea is to dynamically create a child record as needed.

Thanks,

Andrew

Example code:

ObjectContext oc = ClientBaseAdmin.getObjectContext();
CommunicationLog cl = oc.newObject(CommunicationLog.class);
cl.setCommunicationDT(LocalDateTime.now());
cl.setCommunicationType(CommunicationType.find("Email"));
oc.commitChanges();

and in CommunicationType I have

public static CommunicationType find(String value) {
         CommunicationType result = null;
         result = ObjectSelect.query(CommunicationType.class)
                 .where(CommunicationType.DESCRIPTION.eq(value))
                 .selectFirst(ClientBaseAdmin.getObjectContext());

         if (result == null) {
             CommunicationType ct = 
ClientBaseAdmin.getObjectContext().newObject(CommunicationType.class);
             ct.setDescription(value);
             ClientBaseAdmin.getObjectContext().commitChanges();
             result = ct;
         }
         return result;
}


Re: Question on how to properly create parent-child nested dependent objects?

Posted by Nikita Timofeev <nt...@objectstyle.com>.
We are back to what we have started from, it seems that you didn't
create table AUTO_PK_SUPPORT properly. Exception shows that there is
no row for 'CommunicationType' and because of this Cayenne can't
generate primary key.
This is a helper table that is used internally to generate primary
keys if you are using "Cayenne Generated" type.
All your need is to create (I think it is already created) and fill
this table, this can be done from Cayenne Modeler: Tools -> Generate
Database Schema -> Generate PK support flag, or you can try to run
this query directly:

INSERT INTO AUTO_PK_SUPPORT (TABLE_NAME, NEXT_ID)
VALUES ('CommunicationType', 200);

Database schema should be maintained by you, Cayenne can't help you
much with this as it can be dangerous in most cases, everything rest
should be fine, as Ari said you can create and/or modify everything in
one context and save it at the end.

On Tue, Sep 19, 2017 at 4:16 PM, Aristedes Maniatis <ar...@maniatis.org> wrote:
> On 19/9/17 11:01PM, Andrew Willerding wrote:
>> The CommunicationType object does not yet exist permanently in the database table so how or when does it generate the primary key for the object to be referenced by another object before it is committed?  I was hoping to not have to worry about this as a "high-level" user of Cayenne.
>
>
> You are right, you don't need to worry about all that. Just create one context and save it at the end. Cayenne tracks the relationships between objects with a temporary key internally, but you don't need to think about that. Once Caynenne commits, everything is assigned proper primary keys and joined.
>
> Ari
>
>
> --
> -------------------------->
> Aristedes Maniatis
> GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A



-- 
Best regards,
Nikita Timofeev

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Mike Kienenberger <mk...@gmail.com>.
Yes, much easier if it's just a matter of creating objects in a
different order :-)

On Wed, Sep 20, 2017 at 8:45 AM, Nikita Timofeev
<nt...@objectstyle.com> wrote:
> Other option is to create CommunicationType first and then just use it:
>
> CommunicationType type = CommunicationType.find("Email");
>
> CommunicationLog cl = oc.newObject(CommunicationLog.class);
> cl.setCommunicationDT(LocalDateTime.now());
> cl.setCommunicationType(type);
> oc.commitChanges();
>
> In this case everything will be in one context, and you can freely
> commit CommunicationType to DB.
>
> On Wed, Sep 20, 2017 at 3:37 PM, Mike Kienenberger <mk...@gmail.com> wrote:
>> I haven't followed the details, so I don't know if using a separate
>> object context is necessary, but all you need to do to move a data
>> object (in your case "child") to a different context is to call
>> parentContext.localObject(childDataObject) which will return
>> childDataObjectInParentContext.   Note that this requires either a
>> hollow or committed childDataObject as a modified (uncommitted) or new
>> (uncommitted) data object's changes only exist in the
>> childObjectContext.
>>
>> I may also have the syntax for localObject() wrong as I'm probably
>> using an older version of Cayenne than you are.
>>
>>
>>
>> On Wed, Sep 20, 2017 at 8:30 AM, Andrew Willerding
>> <aw...@itsurcom.com> wrote:
>>> I guess my issue is with how independent the commits can be.  Now that I
>>> better understand this, my code example works as Nikita suggested (with the
>>> fix for my problem with the PrimaryKey table) and if I drop the commit
>>> during the creation of the child object otherwise the commit during the
>>> child creation will fail because the parent has not yet been assigned with
>>> the child object.
>>>
>>> My objective is that I want the creation of the child to be completely
>>> independent of the parent object for this situation. To do this I have to
>>> create a new ObjectContext  for the child object to make it independent of
>>> the parent's ObjectContext but when I return the newly created child object
>>> to the parent object I get the following
>>>
>>> Caused by: org.apache.cayenne.CayenneRuntimeException: [v.4.0.B1 Jun 02 2017
>>> 15:11:18] Cannot set object as destination of relationship communicationType
>>> because it is in a different ObjectContext
>>>     at
>>> org.apache.cayenne.CayenneDataObject.willConnect(CayenneDataObject.java:399)
>>>     at
>>> org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneDataObject.java:355)
>>>     at
>>> com.callistacti.clientbase.Database.auto._CommunicationLog.setCommunicationType(_CommunicationLog.java:65)
>>>     at
>>> com.callistacti.clientbase.Panel.PanelGroups.windowClose(PanelGroups.java:423)
>>>
>>> So what I then needed to do is lookup the child object with the same
>>> ObjectContext that the parent was using.
>>>
>>> Out of curiousity, is there any simpler way of doing this?
>>>
>>>
>>>
>>> On 19/09/17 09:16 AM, Aristedes Maniatis wrote:
>>>>
>>>> On 19/9/17 11:01PM, Andrew Willerding wrote:
>>>>>
>>>>> The CommunicationType object does not yet exist permanently in the
>>>>> database table so how or when does it generate the primary key for the
>>>>> object to be referenced by another object before it is committed?  I was
>>>>> hoping to not have to worry about this as a "high-level" user of Cayenne.
>>>>
>>>>
>>>> You are right, you don't need to worry about all that. Just create one
>>>> context and save it at the end. Cayenne tracks the relationships between
>>>> objects with a temporary key internally, but you don't need to think about
>>>> that. Once Caynenne commits, everything is assigned proper primary keys and
>>>> joined.
>>>>
>>>> Ari
>>>>
>>>>
>>>
>
>
>
> --
> Best regards,
> Nikita Timofeev

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Michael Gentry <bl...@gmail.com>.
PS. I did mention you might want to change the last line...


On Wed, Sep 20, 2017 at 10:36 AM, Michael Gentry <bl...@gmail.com>
wrote:

> Hi Mike,
>
> This is 3-4 year old 3.0 code which is working and I haven't updated it
> yet.  That's mainly it...not enough cycles.
>
> mrg
>
>
> On Wed, Sep 20, 2017 at 10:28 AM, Mike Kienenberger <mk...@gmail.com>
> wrote:
>
>> Michael,
>>
>> Why do you suggest
>>
>> DataObjectUtils.objectForPK(destinationContext,
>> contractDesignation.getObjectId());
>>
>> instead of
>>
>> destinationContext.localObject(contractDesignation);
>>
>>
>> ?
>>
>

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Michael Gentry <bl...@gmail.com>.
Hi Mike,

This is 3-4 year old 3.0 code which is working and I haven't updated it
yet.  That's mainly it...not enough cycles.

mrg


On Wed, Sep 20, 2017 at 10:28 AM, Mike Kienenberger <mk...@gmail.com>
wrote:

> Michael,
>
> Why do you suggest
>
> DataObjectUtils.objectForPK(destinationContext,
> contractDesignation.getObjectId());
>
> instead of
>
> destinationContext.localObject(contractDesignation);
>
>
> ?
>

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Mike Kienenberger <mk...@gmail.com>.
Michael,

Why do you suggest

DataObjectUtils.objectForPK(destinationContext,
contractDesignation.getObjectId());

instead of

destinationContext.localObject(contractDesignation);


?



On Wed, Sep 20, 2017 at 9:54 AM, Michael Gentry <bl...@gmail.com> wrote:
> Hi Andrew,
>
> I'm jumping in late here, but I did something very similar to what you are
> trying to do with CommunicationType.find().  I create (auto-populate) a
> reference table record based upon some enum values if missing, or just
> return the reference table record if I find it.  I do this in a completely
> separate (not a child) DataContext and copy the result into the main
> destination context passed into the method.
>
> This is from 3.1, so might vary a bit on the last line if you are on 4.x
> (I'm using a deprecated method there and haven't updated yet):
>
>     public static ContractDesignation fetch(ObjectContext
> destinationContext,
>                                             ContractMethodType
> contractMethod,
>                                             ContractType       contractType,
>                                             FundingVehicleType
> fundingVehicle)
>     {
>         ContractDesignation contractDesignation = null;
>         DataContext         dataContext         =
> CayenneUtils.createDataContext();
>         Expression          exp1                =
> ExpressionFactory.matchExp(CONTRACT_METHOD_PROPERTY, contractMethod);
>         Expression          exp2                =
> ExpressionFactory.matchExp(CONTRACT_TYPE_PROPERTY, contractType);
>         Expression          exp3                =
> ExpressionFactory.matchExp(FUNDING_VEHICLE_PROPERTY, fundingVehicle);
>         Expression          exp                 =
> exp1.andExp(exp2).andExp(exp3);
>         SelectQuery         query               = new
> SelectQuery(ContractDesignation.class, exp);
>
>         @SuppressWarnings("unchecked")
>         List<ContractDesignation> contractDesignations =
> dataContext.performQuery(query);
>
>         // If no contract designation is found, create a new one, else use
> the
>         // one that was found (throwing an exception if too many are found).
>         if (contractDesignations.isEmpty())
>         {
>             contractDesignation =
> dataContext.newObject(ContractDesignation.class);
>
>             contractDesignation.setContractMethod(contractMethod);
>             contractDesignation.setContractType(contractType);
>             contractDesignation.setFundingVehicle(fundingVehicle);
>
>             dataContext.commitChanges();
>         }
>         else if (contractDesignations.size() == 1)
>         {
>             contractDesignation = contractDesignations.get(0);
>         }
>         else
>         {
>             // There can be only one!
>             throw new TooManyResultsException("There can be at most one
> match for ContractDesignation contractMethod='" + contractMethod +
>                                               "' / contractType='" +
> contractType +
>                                               "' / fundingVehicle='" +
> fundingVehicle + "'");
>         }
>
>         // Pull the fetched ContractDesignation into the destination
> ObjectContext.
>         return (ContractDesignation)
> DataObjectUtils.objectForPK(destinationContext,
> contractDesignation.getObjectId());
>     }
>
>
>
>
> On Wed, Sep 20, 2017 at 9:16 AM, Andrew Willerding <awillerding@itsurcom.com
>> wrote:
>
>> I thought of this too but I'm trying to create the child object
>> dynamically without having any impact on the parent object or making the
>> coder of the parent object worry about creating child objects first.
>>
>>
>>
>> On 20/09/17 08:45 AM, Nikita Timofeev wrote:
>>
>>> Other option is to create CommunicationType first and then just use it:
>>>
>>> CommunicationType type = CommunicationType.find("Email");
>>>
>>> CommunicationLog cl = oc.newObject(CommunicationLog.class);
>>> cl.setCommunicationDT(LocalDateTime.now());
>>> cl.setCommunicationType(type);
>>> oc.commitChanges();
>>>
>>> In this case everything will be in one context, and you can freely
>>> commit CommunicationType to DB.
>>>
>>> On Wed, Sep 20, 2017 at 3:37 PM, Mike Kienenberger <mk...@gmail.com>
>>> wrote:
>>>
>>>> I haven't followed the details, so I don't know if using a separate
>>>> object context is necessary, but all you need to do to move a data
>>>> object (in your case "child") to a different context is to call
>>>> parentContext.localObject(childDataObject) which will return
>>>> childDataObjectInParentContext.   Note that this requires either a
>>>> hollow or committed childDataObject as a modified (uncommitted) or new
>>>> (uncommitted) data object's changes only exist in the
>>>> childObjectContext.
>>>>
>>>> I may also have the syntax for localObject() wrong as I'm probably
>>>> using an older version of Cayenne than you are.
>>>>
>>>>
>>>>
>>>> On Wed, Sep 20, 2017 at 8:30 AM, Andrew Willerding
>>>> <aw...@itsurcom.com> wrote:
>>>>
>>>>> I guess my issue is with how independent the commits can be.  Now that I
>>>>> better understand this, my code example works as Nikita suggested (with
>>>>> the
>>>>> fix for my problem with the PrimaryKey table) and if I drop the commit
>>>>> during the creation of the child object otherwise the commit during the
>>>>> child creation will fail because the parent has not yet been assigned
>>>>> with
>>>>> the child object.
>>>>>
>>>>> My objective is that I want the creation of the child to be completely
>>>>> independent of the parent object for this situation. To do this I have
>>>>> to
>>>>> create a new ObjectContext  for the child object to make it independent
>>>>> of
>>>>> the parent's ObjectContext but when I return the newly created child
>>>>> object
>>>>> to the parent object I get the following
>>>>>
>>>>> Caused by: org.apache.cayenne.CayenneRuntimeException: [v.4.0.B1 Jun
>>>>> 02 2017
>>>>> 15:11:18] Cannot set object as destination of relationship
>>>>> communicationType
>>>>> because it is in a different ObjectContext
>>>>>      at
>>>>> org.apache.cayenne.CayenneDataObject.willConnect(CayenneData
>>>>> Object.java:399)
>>>>>      at
>>>>> org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneD
>>>>> ataObject.java:355)
>>>>>      at
>>>>> com.callistacti.clientbase.Database.auto._CommunicationLog.s
>>>>> etCommunicationType(_CommunicationLog.java:65)
>>>>>      at
>>>>> com.callistacti.clientbase.Panel.PanelGroups.windowClose(Pan
>>>>> elGroups.java:423)
>>>>>
>>>>> So what I then needed to do is lookup the child object with the same
>>>>> ObjectContext that the parent was using.
>>>>>
>>>>> Out of curiousity, is there any simpler way of doing this?
>>>>>
>>>>>
>>>>>
>>>>> On 19/09/17 09:16 AM, Aristedes Maniatis wrote:
>>>>>
>>>>>> On 19/9/17 11:01PM, Andrew Willerding wrote:
>>>>>>
>>>>>>> The CommunicationType object does not yet exist permanently in the
>>>>>>> database table so how or when does it generate the primary key for the
>>>>>>> object to be referenced by another object before it is committed?  I
>>>>>>> was
>>>>>>> hoping to not have to worry about this as a "high-level" user of
>>>>>>> Cayenne.
>>>>>>>
>>>>>>
>>>>>> You are right, you don't need to worry about all that. Just create one
>>>>>> context and save it at the end. Cayenne tracks the relationships
>>>>>> between
>>>>>> objects with a temporary key internally, but you don't need to think
>>>>>> about
>>>>>> that. Once Caynenne commits, everything is assigned proper primary
>>>>>> keys and
>>>>>> joined.
>>>>>>
>>>>>> Ari
>>>>>>
>>>>>>
>>>>>>
>>>
>>>
>>

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Andrew Willerding <aw...@itsurcom.com>.
Hi Michael,

I have ended up doing exactly what you did except in Cayenne 4.x using a 
bit of a recursive call cheat as I know the 
ClientBaseAdmin.getObjectContext() should always return the same 
ObjectContext in both the Parent and Child objects.  I left the 
commented out code which was causing me the grief on the commitChanges 
when I used the original ObjectContext.

Parent code

ObjectContext oc = ClientBaseAdmin.getObjectContext();
CommunicationLog cl = oc.newObject(CommunicationLog.class);
cl.setCommunicationDT(LocalDateTime.now());
cl.setCommunicationType( CommunicationType.find("Email"));
cl.setDescription(cl.getCommunicationType().getDescription() + 
",notification msg," + win.selectedItem.getCode() + ",to," + 
contact.getEmail());
oc.commitChanges();

And the child code

     public static CommunicationType find(String value) {
         CommunicationType result = null;
         result = ObjectSelect.query(CommunicationType.class)
                 .where(CommunicationType.DESCRIPTION.eq(value))
                 .selectFirst(ClientBaseAdmin.getObjectContext());

         if (result == null) {
             ObjectContext oc = 
ORMCayenne.getServerRuntime(UI_ClientBase.RESOURCE_DIR + 
UI_ClientBase.MY_CAYENNE_XML_FILE).newContext();
             // ObjectContext oc = ClientBaseAdmin.getObjectContext();
             CommunicationType ct = oc.newObject(CommunicationType.class);
             ct.setDescription(value);
             oc.commitChanges();
             result = find(value);
             //result = ct;
         }
         return result;
     }



On 20/09/17 09:54 AM, Michael Gentry wrote:
> Hi Andrew,
>
> I'm jumping in late here, but I did something very similar to what you are
> trying to do with CommunicationType.find().  I create (auto-populate) a
> reference table record based upon some enum values if missing, or just
> return the reference table record if I find it.  I do this in a completely
> separate (not a child) DataContext and copy the result into the main
> destination context passed into the method.
>
> This is from 3.1, so might vary a bit on the last line if you are on 4.x
> (I'm using a deprecated method there and haven't updated yet):
>
>      public static ContractDesignation fetch(ObjectContext
> destinationContext,
>                                              ContractMethodType
> contractMethod,
>                                              ContractType       contractType,
>                                              FundingVehicleType
> fundingVehicle)
>      {
>          ContractDesignation contractDesignation = null;
>          DataContext         dataContext         =
> CayenneUtils.createDataContext();
>          Expression          exp1                =
> ExpressionFactory.matchExp(CONTRACT_METHOD_PROPERTY, contractMethod);
>          Expression          exp2                =
> ExpressionFactory.matchExp(CONTRACT_TYPE_PROPERTY, contractType);
>          Expression          exp3                =
> ExpressionFactory.matchExp(FUNDING_VEHICLE_PROPERTY, fundingVehicle);
>          Expression          exp                 =
> exp1.andExp(exp2).andExp(exp3);
>          SelectQuery         query               = new
> SelectQuery(ContractDesignation.class, exp);
>
>          @SuppressWarnings("unchecked")
>          List<ContractDesignation> contractDesignations =
> dataContext.performQuery(query);
>
>          // If no contract designation is found, create a new one, else use
> the
>          // one that was found (throwing an exception if too many are found).
>          if (contractDesignations.isEmpty())
>          {
>              contractDesignation =
> dataContext.newObject(ContractDesignation.class);
>
>              contractDesignation.setContractMethod(contractMethod);
>              contractDesignation.setContractType(contractType);
>              contractDesignation.setFundingVehicle(fundingVehicle);
>
>              dataContext.commitChanges();
>          }
>          else if (contractDesignations.size() == 1)
>          {
>              contractDesignation = contractDesignations.get(0);
>          }
>          else
>          {
>              // There can be only one!
>              throw new TooManyResultsException("There can be at most one
> match for ContractDesignation contractMethod='" + contractMethod +
>                                                "' / contractType='" +
> contractType +
>                                                "' / fundingVehicle='" +
> fundingVehicle + "'");
>          }
>
>          // Pull the fetched ContractDesignation into the destination
> ObjectContext.
>          return (ContractDesignation)
> DataObjectUtils.objectForPK(destinationContext,
> contractDesignation.getObjectId());
>      }
>
>
>
>
> On Wed, Sep 20, 2017 at 9:16 AM, Andrew Willerding <awillerding@itsurcom.com
>> wrote:
>> I thought of this too but I'm trying to create the child object
>> dynamically without having any impact on the parent object or making the
>> coder of the parent object worry about creating child objects first.
>>
>>
>>
>> On 20/09/17 08:45 AM, Nikita Timofeev wrote:
>>
>>> Other option is to create CommunicationType first and then just use it:
>>>
>>> CommunicationType type = CommunicationType.find("Email");
>>>
>>> CommunicationLog cl = oc.newObject(CommunicationLog.class);
>>> cl.setCommunicationDT(LocalDateTime.now());
>>> cl.setCommunicationType(type);
>>> oc.commitChanges();
>>>
>>> In this case everything will be in one context, and you can freely
>>> commit CommunicationType to DB.
>>>
>>> On Wed, Sep 20, 2017 at 3:37 PM, Mike Kienenberger <mk...@gmail.com>
>>> wrote:
>>>
>>>> I haven't followed the details, so I don't know if using a separate
>>>> object context is necessary, but all you need to do to move a data
>>>> object (in your case "child") to a different context is to call
>>>> parentContext.localObject(childDataObject) which will return
>>>> childDataObjectInParentContext.   Note that this requires either a
>>>> hollow or committed childDataObject as a modified (uncommitted) or new
>>>> (uncommitted) data object's changes only exist in the
>>>> childObjectContext.
>>>>
>>>> I may also have the syntax for localObject() wrong as I'm probably
>>>> using an older version of Cayenne than you are.
>>>>
>>>>
>>>>
>>>> On Wed, Sep 20, 2017 at 8:30 AM, Andrew Willerding
>>>> <aw...@itsurcom.com> wrote:
>>>>
>>>>> I guess my issue is with how independent the commits can be.  Now that I
>>>>> better understand this, my code example works as Nikita suggested (with
>>>>> the
>>>>> fix for my problem with the PrimaryKey table) and if I drop the commit
>>>>> during the creation of the child object otherwise the commit during the
>>>>> child creation will fail because the parent has not yet been assigned
>>>>> with
>>>>> the child object.
>>>>>
>>>>> My objective is that I want the creation of the child to be completely
>>>>> independent of the parent object for this situation. To do this I have
>>>>> to
>>>>> create a new ObjectContext  for the child object to make it independent
>>>>> of
>>>>> the parent's ObjectContext but when I return the newly created child
>>>>> object
>>>>> to the parent object I get the following
>>>>>
>>>>> Caused by: org.apache.cayenne.CayenneRuntimeException: [v.4.0.B1 Jun
>>>>> 02 2017
>>>>> 15:11:18] Cannot set object as destination of relationship
>>>>> communicationType
>>>>> because it is in a different ObjectContext
>>>>>       at
>>>>> org.apache.cayenne.CayenneDataObject.willConnect(CayenneData
>>>>> Object.java:399)
>>>>>       at
>>>>> org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneD
>>>>> ataObject.java:355)
>>>>>       at
>>>>> com.callistacti.clientbase.Database.auto._CommunicationLog.s
>>>>> etCommunicationType(_CommunicationLog.java:65)
>>>>>       at
>>>>> com.callistacti.clientbase.Panel.PanelGroups.windowClose(Pan
>>>>> elGroups.java:423)
>>>>>
>>>>> So what I then needed to do is lookup the child object with the same
>>>>> ObjectContext that the parent was using.
>>>>>
>>>>> Out of curiousity, is there any simpler way of doing this?
>>>>>
>>>>>
>>>>>
>>>>> On 19/09/17 09:16 AM, Aristedes Maniatis wrote:
>>>>>
>>>>>> On 19/9/17 11:01PM, Andrew Willerding wrote:
>>>>>>
>>>>>>> The CommunicationType object does not yet exist permanently in the
>>>>>>> database table so how or when does it generate the primary key for the
>>>>>>> object to be referenced by another object before it is committed?  I
>>>>>>> was
>>>>>>> hoping to not have to worry about this as a "high-level" user of
>>>>>>> Cayenne.
>>>>>>>
>>>>>> You are right, you don't need to worry about all that. Just create one
>>>>>> context and save it at the end. Cayenne tracks the relationships
>>>>>> between
>>>>>> objects with a temporary key internally, but you don't need to think
>>>>>> about
>>>>>> that. Once Caynenne commits, everything is assigned proper primary
>>>>>> keys and
>>>>>> joined.
>>>>>>
>>>>>> Ari
>>>>>>
>>>>>>
>>>>>>
>>>


Re: Question on how to properly create parent-child nested dependent objects?

Posted by Michael Gentry <bl...@gmail.com>.
Hi Andrew,

I'm jumping in late here, but I did something very similar to what you are
trying to do with CommunicationType.find().  I create (auto-populate) a
reference table record based upon some enum values if missing, or just
return the reference table record if I find it.  I do this in a completely
separate (not a child) DataContext and copy the result into the main
destination context passed into the method.

This is from 3.1, so might vary a bit on the last line if you are on 4.x
(I'm using a deprecated method there and haven't updated yet):

    public static ContractDesignation fetch(ObjectContext
destinationContext,
                                            ContractMethodType
contractMethod,
                                            ContractType       contractType,
                                            FundingVehicleType
fundingVehicle)
    {
        ContractDesignation contractDesignation = null;
        DataContext         dataContext         =
CayenneUtils.createDataContext();
        Expression          exp1                =
ExpressionFactory.matchExp(CONTRACT_METHOD_PROPERTY, contractMethod);
        Expression          exp2                =
ExpressionFactory.matchExp(CONTRACT_TYPE_PROPERTY, contractType);
        Expression          exp3                =
ExpressionFactory.matchExp(FUNDING_VEHICLE_PROPERTY, fundingVehicle);
        Expression          exp                 =
exp1.andExp(exp2).andExp(exp3);
        SelectQuery         query               = new
SelectQuery(ContractDesignation.class, exp);

        @SuppressWarnings("unchecked")
        List<ContractDesignation> contractDesignations =
dataContext.performQuery(query);

        // If no contract designation is found, create a new one, else use
the
        // one that was found (throwing an exception if too many are found).
        if (contractDesignations.isEmpty())
        {
            contractDesignation =
dataContext.newObject(ContractDesignation.class);

            contractDesignation.setContractMethod(contractMethod);
            contractDesignation.setContractType(contractType);
            contractDesignation.setFundingVehicle(fundingVehicle);

            dataContext.commitChanges();
        }
        else if (contractDesignations.size() == 1)
        {
            contractDesignation = contractDesignations.get(0);
        }
        else
        {
            // There can be only one!
            throw new TooManyResultsException("There can be at most one
match for ContractDesignation contractMethod='" + contractMethod +
                                              "' / contractType='" +
contractType +
                                              "' / fundingVehicle='" +
fundingVehicle + "'");
        }

        // Pull the fetched ContractDesignation into the destination
ObjectContext.
        return (ContractDesignation)
DataObjectUtils.objectForPK(destinationContext,
contractDesignation.getObjectId());
    }




On Wed, Sep 20, 2017 at 9:16 AM, Andrew Willerding <awillerding@itsurcom.com
> wrote:

> I thought of this too but I'm trying to create the child object
> dynamically without having any impact on the parent object or making the
> coder of the parent object worry about creating child objects first.
>
>
>
> On 20/09/17 08:45 AM, Nikita Timofeev wrote:
>
>> Other option is to create CommunicationType first and then just use it:
>>
>> CommunicationType type = CommunicationType.find("Email");
>>
>> CommunicationLog cl = oc.newObject(CommunicationLog.class);
>> cl.setCommunicationDT(LocalDateTime.now());
>> cl.setCommunicationType(type);
>> oc.commitChanges();
>>
>> In this case everything will be in one context, and you can freely
>> commit CommunicationType to DB.
>>
>> On Wed, Sep 20, 2017 at 3:37 PM, Mike Kienenberger <mk...@gmail.com>
>> wrote:
>>
>>> I haven't followed the details, so I don't know if using a separate
>>> object context is necessary, but all you need to do to move a data
>>> object (in your case "child") to a different context is to call
>>> parentContext.localObject(childDataObject) which will return
>>> childDataObjectInParentContext.   Note that this requires either a
>>> hollow or committed childDataObject as a modified (uncommitted) or new
>>> (uncommitted) data object's changes only exist in the
>>> childObjectContext.
>>>
>>> I may also have the syntax for localObject() wrong as I'm probably
>>> using an older version of Cayenne than you are.
>>>
>>>
>>>
>>> On Wed, Sep 20, 2017 at 8:30 AM, Andrew Willerding
>>> <aw...@itsurcom.com> wrote:
>>>
>>>> I guess my issue is with how independent the commits can be.  Now that I
>>>> better understand this, my code example works as Nikita suggested (with
>>>> the
>>>> fix for my problem with the PrimaryKey table) and if I drop the commit
>>>> during the creation of the child object otherwise the commit during the
>>>> child creation will fail because the parent has not yet been assigned
>>>> with
>>>> the child object.
>>>>
>>>> My objective is that I want the creation of the child to be completely
>>>> independent of the parent object for this situation. To do this I have
>>>> to
>>>> create a new ObjectContext  for the child object to make it independent
>>>> of
>>>> the parent's ObjectContext but when I return the newly created child
>>>> object
>>>> to the parent object I get the following
>>>>
>>>> Caused by: org.apache.cayenne.CayenneRuntimeException: [v.4.0.B1 Jun
>>>> 02 2017
>>>> 15:11:18] Cannot set object as destination of relationship
>>>> communicationType
>>>> because it is in a different ObjectContext
>>>>      at
>>>> org.apache.cayenne.CayenneDataObject.willConnect(CayenneData
>>>> Object.java:399)
>>>>      at
>>>> org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneD
>>>> ataObject.java:355)
>>>>      at
>>>> com.callistacti.clientbase.Database.auto._CommunicationLog.s
>>>> etCommunicationType(_CommunicationLog.java:65)
>>>>      at
>>>> com.callistacti.clientbase.Panel.PanelGroups.windowClose(Pan
>>>> elGroups.java:423)
>>>>
>>>> So what I then needed to do is lookup the child object with the same
>>>> ObjectContext that the parent was using.
>>>>
>>>> Out of curiousity, is there any simpler way of doing this?
>>>>
>>>>
>>>>
>>>> On 19/09/17 09:16 AM, Aristedes Maniatis wrote:
>>>>
>>>>> On 19/9/17 11:01PM, Andrew Willerding wrote:
>>>>>
>>>>>> The CommunicationType object does not yet exist permanently in the
>>>>>> database table so how or when does it generate the primary key for the
>>>>>> object to be referenced by another object before it is committed?  I
>>>>>> was
>>>>>> hoping to not have to worry about this as a "high-level" user of
>>>>>> Cayenne.
>>>>>>
>>>>>
>>>>> You are right, you don't need to worry about all that. Just create one
>>>>> context and save it at the end. Cayenne tracks the relationships
>>>>> between
>>>>> objects with a temporary key internally, but you don't need to think
>>>>> about
>>>>> that. Once Caynenne commits, everything is assigned proper primary
>>>>> keys and
>>>>> joined.
>>>>>
>>>>> Ari
>>>>>
>>>>>
>>>>>
>>
>>
>

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Andrew Willerding <aw...@itsurcom.com>.
I thought of this too but I'm trying to create the child object 
dynamically without having any impact on the parent object or making the 
coder of the parent object worry about creating child objects first.


On 20/09/17 08:45 AM, Nikita Timofeev wrote:
> Other option is to create CommunicationType first and then just use it:
>
> CommunicationType type = CommunicationType.find("Email");
>
> CommunicationLog cl = oc.newObject(CommunicationLog.class);
> cl.setCommunicationDT(LocalDateTime.now());
> cl.setCommunicationType(type);
> oc.commitChanges();
>
> In this case everything will be in one context, and you can freely
> commit CommunicationType to DB.
>
> On Wed, Sep 20, 2017 at 3:37 PM, Mike Kienenberger <mk...@gmail.com> wrote:
>> I haven't followed the details, so I don't know if using a separate
>> object context is necessary, but all you need to do to move a data
>> object (in your case "child") to a different context is to call
>> parentContext.localObject(childDataObject) which will return
>> childDataObjectInParentContext.   Note that this requires either a
>> hollow or committed childDataObject as a modified (uncommitted) or new
>> (uncommitted) data object's changes only exist in the
>> childObjectContext.
>>
>> I may also have the syntax for localObject() wrong as I'm probably
>> using an older version of Cayenne than you are.
>>
>>
>>
>> On Wed, Sep 20, 2017 at 8:30 AM, Andrew Willerding
>> <aw...@itsurcom.com> wrote:
>>> I guess my issue is with how independent the commits can be.  Now that I
>>> better understand this, my code example works as Nikita suggested (with the
>>> fix for my problem with the PrimaryKey table) and if I drop the commit
>>> during the creation of the child object otherwise the commit during the
>>> child creation will fail because the parent has not yet been assigned with
>>> the child object.
>>>
>>> My objective is that I want the creation of the child to be completely
>>> independent of the parent object for this situation. To do this I have to
>>> create a new ObjectContext  for the child object to make it independent of
>>> the parent's ObjectContext but when I return the newly created child object
>>> to the parent object I get the following
>>>
>>> Caused by: org.apache.cayenne.CayenneRuntimeException: [v.4.0.B1 Jun 02 2017
>>> 15:11:18] Cannot set object as destination of relationship communicationType
>>> because it is in a different ObjectContext
>>>      at
>>> org.apache.cayenne.CayenneDataObject.willConnect(CayenneDataObject.java:399)
>>>      at
>>> org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneDataObject.java:355)
>>>      at
>>> com.callistacti.clientbase.Database.auto._CommunicationLog.setCommunicationType(_CommunicationLog.java:65)
>>>      at
>>> com.callistacti.clientbase.Panel.PanelGroups.windowClose(PanelGroups.java:423)
>>>
>>> So what I then needed to do is lookup the child object with the same
>>> ObjectContext that the parent was using.
>>>
>>> Out of curiousity, is there any simpler way of doing this?
>>>
>>>
>>>
>>> On 19/09/17 09:16 AM, Aristedes Maniatis wrote:
>>>> On 19/9/17 11:01PM, Andrew Willerding wrote:
>>>>> The CommunicationType object does not yet exist permanently in the
>>>>> database table so how or when does it generate the primary key for the
>>>>> object to be referenced by another object before it is committed?  I was
>>>>> hoping to not have to worry about this as a "high-level" user of Cayenne.
>>>>
>>>> You are right, you don't need to worry about all that. Just create one
>>>> context and save it at the end. Cayenne tracks the relationships between
>>>> objects with a temporary key internally, but you don't need to think about
>>>> that. Once Caynenne commits, everything is assigned proper primary keys and
>>>> joined.
>>>>
>>>> Ari
>>>>
>>>>
>
>


Re: Question on how to properly create parent-child nested dependent objects?

Posted by Nikita Timofeev <nt...@objectstyle.com>.
Other option is to create CommunicationType first and then just use it:

CommunicationType type = CommunicationType.find("Email");

CommunicationLog cl = oc.newObject(CommunicationLog.class);
cl.setCommunicationDT(LocalDateTime.now());
cl.setCommunicationType(type);
oc.commitChanges();

In this case everything will be in one context, and you can freely
commit CommunicationType to DB.

On Wed, Sep 20, 2017 at 3:37 PM, Mike Kienenberger <mk...@gmail.com> wrote:
> I haven't followed the details, so I don't know if using a separate
> object context is necessary, but all you need to do to move a data
> object (in your case "child") to a different context is to call
> parentContext.localObject(childDataObject) which will return
> childDataObjectInParentContext.   Note that this requires either a
> hollow or committed childDataObject as a modified (uncommitted) or new
> (uncommitted) data object's changes only exist in the
> childObjectContext.
>
> I may also have the syntax for localObject() wrong as I'm probably
> using an older version of Cayenne than you are.
>
>
>
> On Wed, Sep 20, 2017 at 8:30 AM, Andrew Willerding
> <aw...@itsurcom.com> wrote:
>> I guess my issue is with how independent the commits can be.  Now that I
>> better understand this, my code example works as Nikita suggested (with the
>> fix for my problem with the PrimaryKey table) and if I drop the commit
>> during the creation of the child object otherwise the commit during the
>> child creation will fail because the parent has not yet been assigned with
>> the child object.
>>
>> My objective is that I want the creation of the child to be completely
>> independent of the parent object for this situation. To do this I have to
>> create a new ObjectContext  for the child object to make it independent of
>> the parent's ObjectContext but when I return the newly created child object
>> to the parent object I get the following
>>
>> Caused by: org.apache.cayenne.CayenneRuntimeException: [v.4.0.B1 Jun 02 2017
>> 15:11:18] Cannot set object as destination of relationship communicationType
>> because it is in a different ObjectContext
>>     at
>> org.apache.cayenne.CayenneDataObject.willConnect(CayenneDataObject.java:399)
>>     at
>> org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneDataObject.java:355)
>>     at
>> com.callistacti.clientbase.Database.auto._CommunicationLog.setCommunicationType(_CommunicationLog.java:65)
>>     at
>> com.callistacti.clientbase.Panel.PanelGroups.windowClose(PanelGroups.java:423)
>>
>> So what I then needed to do is lookup the child object with the same
>> ObjectContext that the parent was using.
>>
>> Out of curiousity, is there any simpler way of doing this?
>>
>>
>>
>> On 19/09/17 09:16 AM, Aristedes Maniatis wrote:
>>>
>>> On 19/9/17 11:01PM, Andrew Willerding wrote:
>>>>
>>>> The CommunicationType object does not yet exist permanently in the
>>>> database table so how or when does it generate the primary key for the
>>>> object to be referenced by another object before it is committed?  I was
>>>> hoping to not have to worry about this as a "high-level" user of Cayenne.
>>>
>>>
>>> You are right, you don't need to worry about all that. Just create one
>>> context and save it at the end. Cayenne tracks the relationships between
>>> objects with a temporary key internally, but you don't need to think about
>>> that. Once Caynenne commits, everything is assigned proper primary keys and
>>> joined.
>>>
>>> Ari
>>>
>>>
>>



-- 
Best regards,
Nikita Timofeev

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Mike Kienenberger <mk...@gmail.com>.
I haven't followed the details, so I don't know if using a separate
object context is necessary, but all you need to do to move a data
object (in your case "child") to a different context is to call
parentContext.localObject(childDataObject) which will return
childDataObjectInParentContext.   Note that this requires either a
hollow or committed childDataObject as a modified (uncommitted) or new
(uncommitted) data object's changes only exist in the
childObjectContext.

I may also have the syntax for localObject() wrong as I'm probably
using an older version of Cayenne than you are.



On Wed, Sep 20, 2017 at 8:30 AM, Andrew Willerding
<aw...@itsurcom.com> wrote:
> I guess my issue is with how independent the commits can be.  Now that I
> better understand this, my code example works as Nikita suggested (with the
> fix for my problem with the PrimaryKey table) and if I drop the commit
> during the creation of the child object otherwise the commit during the
> child creation will fail because the parent has not yet been assigned with
> the child object.
>
> My objective is that I want the creation of the child to be completely
> independent of the parent object for this situation. To do this I have to
> create a new ObjectContext  for the child object to make it independent of
> the parent's ObjectContext but when I return the newly created child object
> to the parent object I get the following
>
> Caused by: org.apache.cayenne.CayenneRuntimeException: [v.4.0.B1 Jun 02 2017
> 15:11:18] Cannot set object as destination of relationship communicationType
> because it is in a different ObjectContext
>     at
> org.apache.cayenne.CayenneDataObject.willConnect(CayenneDataObject.java:399)
>     at
> org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneDataObject.java:355)
>     at
> com.callistacti.clientbase.Database.auto._CommunicationLog.setCommunicationType(_CommunicationLog.java:65)
>     at
> com.callistacti.clientbase.Panel.PanelGroups.windowClose(PanelGroups.java:423)
>
> So what I then needed to do is lookup the child object with the same
> ObjectContext that the parent was using.
>
> Out of curiousity, is there any simpler way of doing this?
>
>
>
> On 19/09/17 09:16 AM, Aristedes Maniatis wrote:
>>
>> On 19/9/17 11:01PM, Andrew Willerding wrote:
>>>
>>> The CommunicationType object does not yet exist permanently in the
>>> database table so how or when does it generate the primary key for the
>>> object to be referenced by another object before it is committed?  I was
>>> hoping to not have to worry about this as a "high-level" user of Cayenne.
>>
>>
>> You are right, you don't need to worry about all that. Just create one
>> context and save it at the end. Cayenne tracks the relationships between
>> objects with a temporary key internally, but you don't need to think about
>> that. Once Caynenne commits, everything is assigned proper primary keys and
>> joined.
>>
>> Ari
>>
>>
>

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Andrew Willerding <aw...@itsurcom.com>.
I guess my issue is with how independent the commits can be.  Now that I 
better understand this, my code example works as Nikita suggested (with 
the fix for my problem with the PrimaryKey table) and if I drop the 
commit during the creation of the child object otherwise the commit 
during the child creation will fail because the parent has not yet been 
assigned with the child object.

My objective is that I want the creation of the child to be completely 
independent of the parent object for this situation. To do this I have 
to create a new ObjectContext  for the child object to make it 
independent of the parent's ObjectContext but when I return the newly 
created child object to the parent object I get the following

Caused by: org.apache.cayenne.CayenneRuntimeException: [v.4.0.B1 Jun 02 
2017 15:11:18] Cannot set object as destination of relationship 
communicationType because it is in a different ObjectContext
     at 
org.apache.cayenne.CayenneDataObject.willConnect(CayenneDataObject.java:399)
     at 
org.apache.cayenne.CayenneDataObject.setToOneTarget(CayenneDataObject.java:355)
     at 
com.callistacti.clientbase.Database.auto._CommunicationLog.setCommunicationType(_CommunicationLog.java:65)
     at 
com.callistacti.clientbase.Panel.PanelGroups.windowClose(PanelGroups.java:423)

So what I then needed to do is lookup the child object with the same 
ObjectContext that the parent was using.

Out of curiousity, is there any simpler way of doing this?


On 19/09/17 09:16 AM, Aristedes Maniatis wrote:
> On 19/9/17 11:01PM, Andrew Willerding wrote:
>> The CommunicationType object does not yet exist permanently in the database table so how or when does it generate the primary key for the object to be referenced by another object before it is committed?  I was hoping to not have to worry about this as a "high-level" user of Cayenne.
>
> You are right, you don't need to worry about all that. Just create one context and save it at the end. Cayenne tracks the relationships between objects with a temporary key internally, but you don't need to think about that. Once Caynenne commits, everything is assigned proper primary keys and joined.
>
> Ari
>
>


Re: Question on how to properly create parent-child nested dependent objects?

Posted by Aristedes Maniatis <ar...@maniatis.org>.
On 19/9/17 11:01PM, Andrew Willerding wrote:
> The CommunicationType object does not yet exist permanently in the database table so how or when does it generate the primary key for the object to be referenced by another object before it is committed?  I was hoping to not have to worry about this as a "high-level" user of Cayenne.


You are right, you don't need to worry about all that. Just create one context and save it at the end. Cayenne tracks the relationships between objects with a temporary key internally, but you don't need to think about that. Once Caynenne commits, everything is assigned proper primary keys and joined.

Ari


-- 
-------------------------->
Aristedes Maniatis
GPG fingerprint CBFB 84B4 738D 4E87 5E5C  5EFA EF6A 7D2E 3E49 102A

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Andrew Willerding <aw...@itsurcom.com>.
I tried your suggestion to take out the commit inside the find but now 
I'm getting the No Rows error.  I am using Cayenne generated primary 
keys on all my tables. This is something I don't understand on how 
Cayenne works internally.  The CommunicationType object does not yet 
exist permanently in the database table so how or when does it generate 
the primary key for the object to be referenced by another object before 
it is committed?  I was hoping to not have to worry about this as a 
"high-level" user of Cayenne.

I think what I need to do is to retrieve and/or create the 
CommunicationType object first to make sure it exists and committed and 
then use it in my CommunicationLog object instead of trying to 
dynamically create one during the creation of the other. It's a little 
less convenient as I have to consider it during my coding.  I also read 
through the "ObjectContext Nesting" section of the Cayenne documentation 
but the way I understand it is that the commits cascade from the parent 
downwards which basically works opposite to what I'm trying to achieve 
which is committing the children first to enable the proper creation of 
the parent object.

Please correct me if I'm wrong.  ;-)

Caused by: java.sql.SQLException: No rows for 'CommunicationType'
     at 
org.apache.cayenne.dba.mysql.MySQLPkGenerator.getLongPrimaryKey(MySQLPkGenerator.java:157)
     at 
org.apache.cayenne.dba.mysql.MySQLPkGenerator.longPkFromDatabase(MySQLPkGenerator.java:81)
     at 
org.apache.cayenne.dba.JdbcPkGenerator.generatePk(JdbcPkGenerator.java:230)
     at 
org.apache.cayenne.access.DataDomainInsertBucket.createPermIds(DataDomainInsertBucket.java:162)
     at 
org.apache.cayenne.access.DataDomainInsertBucket.appendQueriesInternal(DataDomainInsertBucket.java:73)
     at 
org.apache.cayenne.access.DataDomainSyncBucket.appendQueries(DataDomainSyncBucket.java:78)
     at 
org.apache.cayenne.access.DataDomainFlushAction.preprocess(DataDomainFlushAction.java:185)
     at 
org.apache.cayenne.access.DataDomainFlushAction.flush(DataDomainFlushAction.java:143)
     at 
org.apache.cayenne.access.DataDomain.onSyncFlush(DataDomain.java:633)
     at 
org.apache.cayenne.access.DataDomain.onSyncNoFilters(DataDomain.java:603)
     at 
org.apache.cayenne.access.DataDomain$DataDomainSyncFilterChain.onSync(DataDomain.java:764)
     at 
org.apache.cayenne.tx.TransactionFilter$1.perform(TransactionFilter.java:73)
     at 
org.apache.cayenne.tx.TransactionFilter$1.perform(TransactionFilter.java:70)
     at 
org.apache.cayenne.tx.DefaultTransactionManager.performInTransaction(DefaultTransactionManager.java:87)
     at 
org.apache.cayenne.tx.DefaultTransactionManager.performInLocalTransaction(DefaultTransactionManager.java:59)
     at 
org.apache.cayenne.tx.DefaultTransactionManager.performInTransaction(DefaultTransactionManager.java:52)
     at 
org.apache.cayenne.tx.DefaultTransactionManager.performInTransaction(DefaultTransactionManager.java:40)
     at 
org.apache.cayenne.tx.TransactionFilter.onSync(TransactionFilter.java:70)
     at 
org.apache.cayenne.access.DataDomain$DataDomainSyncFilterChain.onSync(DataDomain.java:764)
     at org.apache.cayenne.access.DataDomain.onSync(DataDomain.java:590)
     at 
org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:742)


On 19/09/17 03:21 AM, Nikita Timofeev wrote:
> Ok, looked closer at your code, commitChanges() call inside find()
> method doing not what you expect, it flushes ALL changes in a given
> context to DB, and that includes partially created CommunicationLog
> object.
> Generally there is no need to commit every object, you can create and
> link as many objects as you need, so you can just skip commitChanges()
> call inside find() method or you should find CommunicationType first
> and then create CommunicationLog.
>
>
> On Mon, Sep 18, 2017 at 7:08 PM, Andrew Willerding
> <aw...@itsurcom.com> wrote:
>> Hi Nikita,
>>
>> Based on what you said below, I rebuilt my Database Schema from scratch but
>> now I'm getting the error below.  The validation is failing the line 34
>>
>>   ClientBaseAdmin.getObjectContext().commitChanges();
>>
>> because of the line 418
>>
>> cl.setCommunicationType(CommunicationType.find("Email"));
>>
>> To me it looks like the commit can't happen in the child record because the
>> commit from the parent record is incomplete and no record is created at all.
>>
>> Andrew
>>
>>
>> Caused by: org.apache.cayenne.validation.ValidationException: [v.4.0.B1 Jun
>> 02 2017 15:11:18] Validation failures: Validation failure for
>> com.callistacti.clientbase.Database.CommunicationLog.communicationType:
>> "communicationType"  is required.
>> Validation failure for
>> com.callistacti.clientbase.Database.CommunicationLog.communicationType:
>> "communicationType"  is required.
>>      at
>> org.apache.cayenne.access.ObjectStoreGraphDiff.validateAndCheckNoop(ObjectStoreGraphDiff.java:113)
>>      at
>> org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:734)
>>      at
>> org.apache.cayenne.access.DataContext.commitChanges(DataContext.java:691)
>>      at
>> com.callistacti.clientbase.Database.CommunicationType.find(CommunicationType.java:34)
>>      at
>> com.callistacti.clientbase.Panel.PanelGroups.windowClose(PanelGroups.java:418)
>>      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>>      at
>> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>>      at
>> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>>      at java.lang.reflect.Method.invoke(Method.java:498)
>>      at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)
>>
>>
>>
>> On 18/09/17 11:40 AM, Nikita Timofeev wrote:
>>> Hi Andrew,
>>>
>>> Can you provide stack trace for the exception you got (Cayenne related
>>> part of it)?
>>> It seems to me that you have problem with PK generation, not with your
>>> data objects.
>>> Your code looks fine to me and should work.
>>>
>>> On Mon, Sep 18, 2017 at 6:30 PM, Andrew Willerding
>>> <aw...@itsurcom.com> wrote:
>>>> Hi,
>>>>
>>>> I am trying to create a DB record where a dependency record may not yet
>>>> exist and I'm getting a "No rows for ..." error.  I don't understand how
>>>> I
>>>> should create the child record that will be used for the parent object so
>>>> it
>>>> can be referenced by the parent object without getting an error.  The
>>>> idea
>>>> is to dynamically create a child record as needed.
>>>>
>>>> Thanks,
>>>>
>>>> Andrew
>>>>
>>>> Example code:
>>>>
>>>> ObjectContext oc = ClientBaseAdmin.getObjectContext();
>>>> CommunicationLog cl = oc.newObject(CommunicationLog.class);
>>>> cl.setCommunicationDT(LocalDateTime.now());
>>>> cl.setCommunicationType(CommunicationType.find("Email"));
>>>> oc.commitChanges();
>>>>
>>>> and in CommunicationType I have
>>>>
>>>> public static CommunicationType find(String value) {
>>>>           CommunicationType result = null;
>>>>           result = ObjectSelect.query(CommunicationType.class)
>>>>                   .where(CommunicationType.DESCRIPTION.eq(value))
>>>>                   .selectFirst(ClientBaseAdmin.getObjectContext());
>>>>
>>>>           if (result == null) {
>>>>               CommunicationType ct =
>>>> ClientBaseAdmin.getObjectContext().newObject(CommunicationType.class);
>>>>               ct.setDescription(value);
>>>>               ClientBaseAdmin.getObjectContext().commitChanges();
>>>>               result = ct;
>>>>           }
>>>>           return result;
>>>> }
>>>>
>>>
>
>


Re: Question on how to properly create parent-child nested dependent objects?

Posted by Nikita Timofeev <nt...@objectstyle.com>.
Ok, looked closer at your code, commitChanges() call inside find()
method doing not what you expect, it flushes ALL changes in a given
context to DB, and that includes partially created CommunicationLog
object.
Generally there is no need to commit every object, you can create and
link as many objects as you need, so you can just skip commitChanges()
call inside find() method or you should find CommunicationType first
and then create CommunicationLog.


On Mon, Sep 18, 2017 at 7:08 PM, Andrew Willerding
<aw...@itsurcom.com> wrote:
> Hi Nikita,
>
> Based on what you said below, I rebuilt my Database Schema from scratch but
> now I'm getting the error below.  The validation is failing the line 34
>
>  ClientBaseAdmin.getObjectContext().commitChanges();
>
> because of the line 418
>
> cl.setCommunicationType(CommunicationType.find("Email"));
>
> To me it looks like the commit can't happen in the child record because the
> commit from the parent record is incomplete and no record is created at all.
>
> Andrew
>
>
> Caused by: org.apache.cayenne.validation.ValidationException: [v.4.0.B1 Jun
> 02 2017 15:11:18] Validation failures: Validation failure for
> com.callistacti.clientbase.Database.CommunicationLog.communicationType:
> "communicationType"  is required.
> Validation failure for
> com.callistacti.clientbase.Database.CommunicationLog.communicationType:
> "communicationType"  is required.
>     at
> org.apache.cayenne.access.ObjectStoreGraphDiff.validateAndCheckNoop(ObjectStoreGraphDiff.java:113)
>     at
> org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:734)
>     at
> org.apache.cayenne.access.DataContext.commitChanges(DataContext.java:691)
>     at
> com.callistacti.clientbase.Database.CommunicationType.find(CommunicationType.java:34)
>     at
> com.callistacti.clientbase.Panel.PanelGroups.windowClose(PanelGroups.java:418)
>     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
>     at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
>     at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
>     at java.lang.reflect.Method.invoke(Method.java:498)
>     at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)
>
>
>
> On 18/09/17 11:40 AM, Nikita Timofeev wrote:
>>
>> Hi Andrew,
>>
>> Can you provide stack trace for the exception you got (Cayenne related
>> part of it)?
>> It seems to me that you have problem with PK generation, not with your
>> data objects.
>> Your code looks fine to me and should work.
>>
>> On Mon, Sep 18, 2017 at 6:30 PM, Andrew Willerding
>> <aw...@itsurcom.com> wrote:
>>>
>>> Hi,
>>>
>>> I am trying to create a DB record where a dependency record may not yet
>>> exist and I'm getting a "No rows for ..." error.  I don't understand how
>>> I
>>> should create the child record that will be used for the parent object so
>>> it
>>> can be referenced by the parent object without getting an error.  The
>>> idea
>>> is to dynamically create a child record as needed.
>>>
>>> Thanks,
>>>
>>> Andrew
>>>
>>> Example code:
>>>
>>> ObjectContext oc = ClientBaseAdmin.getObjectContext();
>>> CommunicationLog cl = oc.newObject(CommunicationLog.class);
>>> cl.setCommunicationDT(LocalDateTime.now());
>>> cl.setCommunicationType(CommunicationType.find("Email"));
>>> oc.commitChanges();
>>>
>>> and in CommunicationType I have
>>>
>>> public static CommunicationType find(String value) {
>>>          CommunicationType result = null;
>>>          result = ObjectSelect.query(CommunicationType.class)
>>>                  .where(CommunicationType.DESCRIPTION.eq(value))
>>>                  .selectFirst(ClientBaseAdmin.getObjectContext());
>>>
>>>          if (result == null) {
>>>              CommunicationType ct =
>>> ClientBaseAdmin.getObjectContext().newObject(CommunicationType.class);
>>>              ct.setDescription(value);
>>>              ClientBaseAdmin.getObjectContext().commitChanges();
>>>              result = ct;
>>>          }
>>>          return result;
>>> }
>>>
>>
>>
>



-- 
Best regards,
Nikita Timofeev

Re: Question on how to properly create parent-child nested dependent objects?

Posted by Andrew Willerding <aw...@itsurcom.com>.
Hi Nikita,

Based on what you said below, I rebuilt my Database Schema from scratch 
but now I'm getting the error below.  The validation is failing the line 34

  ClientBaseAdmin.getObjectContext().commitChanges();

because of the line 418

cl.setCommunicationType(CommunicationType.find("Email"));

To me it looks like the commit can't happen in the child record because 
the commit from the parent record is incomplete and no record is created 
at all.

Andrew


Caused by: org.apache.cayenne.validation.ValidationException: [v.4.0.B1 
Jun 02 2017 15:11:18] Validation failures: Validation failure for 
com.callistacti.clientbase.Database.CommunicationLog.communicationType: 
"communicationType"  is required.
Validation failure for 
com.callistacti.clientbase.Database.CommunicationLog.communicationType: 
"communicationType"  is required.
     at 
org.apache.cayenne.access.ObjectStoreGraphDiff.validateAndCheckNoop(ObjectStoreGraphDiff.java:113)
     at 
org.apache.cayenne.access.DataContext.flushToParent(DataContext.java:734)
     at 
org.apache.cayenne.access.DataContext.commitChanges(DataContext.java:691)
     at 
com.callistacti.clientbase.Database.CommunicationType.find(CommunicationType.java:34)
     at 
com.callistacti.clientbase.Panel.PanelGroups.windowClose(PanelGroups.java:418)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at 
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
     at 
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
     at java.lang.reflect.Method.invoke(Method.java:498)
     at 
com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:510)


On 18/09/17 11:40 AM, Nikita Timofeev wrote:
> Hi Andrew,
>
> Can you provide stack trace for the exception you got (Cayenne related
> part of it)?
> It seems to me that you have problem with PK generation, not with your
> data objects.
> Your code looks fine to me and should work.
>
> On Mon, Sep 18, 2017 at 6:30 PM, Andrew Willerding
> <aw...@itsurcom.com> wrote:
>> Hi,
>>
>> I am trying to create a DB record where a dependency record may not yet
>> exist and I'm getting a "No rows for ..." error.  I don't understand how I
>> should create the child record that will be used for the parent object so it
>> can be referenced by the parent object without getting an error.  The idea
>> is to dynamically create a child record as needed.
>>
>> Thanks,
>>
>> Andrew
>>
>> Example code:
>>
>> ObjectContext oc = ClientBaseAdmin.getObjectContext();
>> CommunicationLog cl = oc.newObject(CommunicationLog.class);
>> cl.setCommunicationDT(LocalDateTime.now());
>> cl.setCommunicationType(CommunicationType.find("Email"));
>> oc.commitChanges();
>>
>> and in CommunicationType I have
>>
>> public static CommunicationType find(String value) {
>>          CommunicationType result = null;
>>          result = ObjectSelect.query(CommunicationType.class)
>>                  .where(CommunicationType.DESCRIPTION.eq(value))
>>                  .selectFirst(ClientBaseAdmin.getObjectContext());
>>
>>          if (result == null) {
>>              CommunicationType ct =
>> ClientBaseAdmin.getObjectContext().newObject(CommunicationType.class);
>>              ct.setDescription(value);
>>              ClientBaseAdmin.getObjectContext().commitChanges();
>>              result = ct;
>>          }
>>          return result;
>> }
>>
>
>


Re: Question on how to properly create parent-child nested dependent objects?

Posted by Nikita Timofeev <nt...@objectstyle.com>.
Hi Andrew,

Can you provide stack trace for the exception you got (Cayenne related
part of it)?
It seems to me that you have problem with PK generation, not with your
data objects.
Your code looks fine to me and should work.

On Mon, Sep 18, 2017 at 6:30 PM, Andrew Willerding
<aw...@itsurcom.com> wrote:
> Hi,
>
> I am trying to create a DB record where a dependency record may not yet
> exist and I'm getting a "No rows for ..." error.  I don't understand how I
> should create the child record that will be used for the parent object so it
> can be referenced by the parent object without getting an error.  The idea
> is to dynamically create a child record as needed.
>
> Thanks,
>
> Andrew
>
> Example code:
>
> ObjectContext oc = ClientBaseAdmin.getObjectContext();
> CommunicationLog cl = oc.newObject(CommunicationLog.class);
> cl.setCommunicationDT(LocalDateTime.now());
> cl.setCommunicationType(CommunicationType.find("Email"));
> oc.commitChanges();
>
> and in CommunicationType I have
>
> public static CommunicationType find(String value) {
>         CommunicationType result = null;
>         result = ObjectSelect.query(CommunicationType.class)
>                 .where(CommunicationType.DESCRIPTION.eq(value))
>                 .selectFirst(ClientBaseAdmin.getObjectContext());
>
>         if (result == null) {
>             CommunicationType ct =
> ClientBaseAdmin.getObjectContext().newObject(CommunicationType.class);
>             ct.setDescription(value);
>             ClientBaseAdmin.getObjectContext().commitChanges();
>             result = ct;
>         }
>         return result;
> }
>



-- 
Best regards,
Nikita Timofeev