cayenne-user mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Michael Gentry <blackn...@gmail.com>
Subject Re: Question on how to properly create parent-child nested dependent objects?
Date Wed, 20 Sep 2017 13:54:01 GMT
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
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message