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

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

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

Andrew Willerding-2
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;
}

Reply | Threaded
Open this post in threaded view
|

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

Nikita Timofeev
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
<[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|

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

Andrew Willerding-2
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
> <[hidden email]> 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;
>> }
>>
>
>

Reply | Threaded
Open this post in threaded view
|

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

Nikita Timofeev
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
<[hidden email]> 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
>> <[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|

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

Andrew Willerding-2
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
> <[hidden email]> 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
>>> <[hidden email]> 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;
>>>> }
>>>>
>>>
>
>

Reply | Threaded
Open this post in threaded view
|

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

Aristedes Maniatis-2
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
Reply | Threaded
Open this post in threaded view
|

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

Nikita Timofeev
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 <[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|

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

Andrew Willerding-2
In reply to this post by Aristedes Maniatis-2
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
>
>

Reply | Threaded
Open this post in threaded view
|

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

Mike Kienenberger
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
<[hidden email]> 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
>>
>>
>
Reply | Threaded
Open this post in threaded view
|

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

Nikita Timofeev
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 <[hidden email]> 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
> <[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|

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

Mike Kienenberger
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
<[hidden email]> 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 <[hidden email]> 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
>> <[hidden email]> 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
Reply | Threaded
Open this post in threaded view
|

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

Andrew Willerding-2
In reply to this post by Nikita Timofeev
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 <[hidden email]> 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
>> <[hidden email]> 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
>>>>
>>>>
>
>

Reply | Threaded
Open this post in threaded view
|

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

Michael Gentry
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 <[hidden email]
> 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 <[hidden email]>
>> 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
>>> <[hidden email]> 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
>>>>>
>>>>>
>>>>>
>>
>>
>
Reply | Threaded
Open this post in threaded view
|

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

Andrew Willerding-2
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 <[hidden email]
>> 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 <[hidden email]>
>>> 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
>>>> <[hidden email]> 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
>>>>>>
>>>>>>
>>>>>>
>>>

Reply | Threaded
Open this post in threaded view
|

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

Mike Kienenberger
In reply to this post by Michael Gentry
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 <[hidden email]> 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 <[hidden email]
>> 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 <[hidden email]>
>>> 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
>>>> <[hidden email]> 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
>>>>>>
>>>>>>
>>>>>>
>>>
>>>
>>
Reply | Threaded
Open this post in threaded view
|

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

Michael Gentry
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 <[hidden email]>
wrote:

> Michael,
>
> Why do you suggest
>
> DataObjectUtils.objectForPK(destinationContext,
> contractDesignation.getObjectId());
>
> instead of
>
> destinationContext.localObject(contractDesignation);
>
>
> ?
>
Reply | Threaded
Open this post in threaded view
|

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

Michael Gentry
PS. I did mention you might want to change the last line...


On Wed, Sep 20, 2017 at 10:36 AM, Michael Gentry <[hidden email]>
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 <[hidden email]>
> wrote:
>
>> Michael,
>>
>> Why do you suggest
>>
>> DataObjectUtils.objectForPK(destinationContext,
>> contractDesignation.getObjectId());
>>
>> instead of
>>
>> destinationContext.localObject(contractDesignation);
>>
>>
>> ?
>>
>