Hi,
Discussion posts and replies are publicly visible
It's fairly simple, all you need to do is set the parent table foreign key value in each member of the child table array when you're creating them (or just before writing to the DB if necessary). No "looping" per se is needed, though one of the easier ways to populate every member of an array with a certain value can sometimes be using a!forEach()... but the exact implementation really kinda depends on the subtleties of your exact implementation so far.
Mike, If I take a little example: some contacts are linked to a customer.
Customer (id, name)Contact (id, name, fk_customer_id)
I need to create 3 contacts linked to 1 customer in a Process model.
Do I need to use a "Write to Multiple Data Store Entities" to store the whole data in the DB, or do I need to create two consecutive "Write to Data Store Entities" smart services (create the customer first, then the contacts) ?
Two consecutive write to datastore nodes would be much safer. It ensures that you won't even start writing contacts with dangling pointers until the object of their pointer is fully built. This is also a good approach because you won't use Appian to get the primary key of the customer before writing it (which invites race conditions) but rather rely on the DB's sequencer to get you the next unused ID.
You can't possibly use that to populate the children with the right FK reference if they were written first, but you can extract it from the Stored Values output of the first Write to Datastore node. You can save that as a PV, then throw a script task in between the two Write to Datastore nodes to explicitly plop the FK reference into each of the contacts in a forEach, then write them.
Just to confirm, this would be my default approach as well.
Personally, I only use Mutliple WTDS nodes when i'm dealing with already-existing rows and with no question as to whether they already exist and the CDTs i'm dealing with are populated or not. (And even then, really only when there's a tight crunch on the number of nodes I can use in that particular process flow.) Otherwise it's always single-WTDS nodes for me.
Thank you Mike, David,
I've created a little example below and in the Script task, I've put a little script containing a foreach to set the FKs.
It works fine, but it couldn't be simpler ?I said to myself that maybe there could have a more direct way without a foreach ?
This doesn't seem so bad, to me. It's the sort of thing that only needs to be done the "first time", as it were. If you were in some crunch to reduce the total number of nodes to the absolute minimum, then I assume the "save IDs to FK" could be condensed either into the data outputs of "Write Customer", or the inputs of "Write Contacts", though either of these approaches would increase the complexity in the target node by a larger factor than what you'd be reducing the process flow by.
While there are no issues with a!forEach() for this approach, you can also accomplish this with the makerange() function, save into the child FK's directly, if you are looking for different options. The performance of makerange() is very scalable with 10,000 rows taking only 2-3 ms to complete, with a!forEach() just over 150ms in my testing.
makerange(count(pv!childCDT),pv!parentCDT.PK) -> Save Into -> pv!childCDT.FK
Also as an unrelated best practice, I would suggest adding a Terminate event to that end node. For maintenance purposes, if any of the nodes fail and have to be restarted, the process will not complete until the node with error has been manually cancelled, unless a Terminate event is added.
As an aside, why would you use "makerange" (which seems to be undocumented?) when we can use repeat() which seems to do the same thing you describe?
I'll have to admit I never noticed makerange() was not included in Appian Documentation. However, while it is not noted there, Appian does provide a shortcut-entry to select it, and also unlike the undocumented fn!try(), it has a definition listed - the existence of those had put it on my approved list in the past. Might be a good question for Appian Support!
In the interim, I would agree fn!repeat() would be the better choice based on the documentation reference and same performance/functionality :)
I don't see makerange() as a function in my instance of Appian - I would guess that it is probably from a plugin.
Thanks a lot for your replies.It will give me some new ideas for my next processes.
Thanks for confirming Peter. I wasn't able to find any references in our plugins, but then I did see one note on the Community here regarding makerange() in Appian v6, circa 2009 (below) - our environment started way back in the 5.6 days in 2007 (on 20.3 currently). Don't think that documentation is even posted anymore
>>>>>
makerange() is documented as follows in Version 6: makerange() This function will generate a list of values for a given range. i.e. makerange(4) = {1,2,3,4} ; makerange(4,55) = {55,55,55,55}
<<<<<
Wow. Talk about legacy. To confirm, in my modern (newer) 20.4 environment, makerange() does not function even as an undocumented function (like try() does), so this must be a legacy remnant from the ancient versions as you mentioned.
Yea, that appears to be the case - definitely an artifact! We'll be swapping these references out for repeat() and enumerate() tout suite here. Not sure when I might have noticed that if not for this thread!