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 <[email protected]> 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 <[email protected] >> 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 <[email protected]> >>> 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 >>>> <[email protected]> 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 >>>>>> >>>>>> >>>>>> >>> >>> >>
