cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrew Willerding <awillerd...@itsurcom.com>
Subject Re: Question on how to properly create parent-child nested dependent objects?
Date Wed, 20 Sep 2017 14:26:07 GMT
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 <mkienenb@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
>>>> <awillerding@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
>>>>>>
>>>>>>
>>>>>>
>>>


Mime
View raw message