How to add the data to DB within a 2 tables 1-N relation?

Certified Senior Developer

Hi,

When I have to add data within a 1-1 relation between 2 tables, I call the "Write to data store entity" Smart Service to add the new record in the parent table and then, from this component output, I retrieve the generated key Id, to set the Foreign Key in the child table.
How would you do for a 1-N relation?
Is there any way to add the data in the 2 tables (1 record in the parent table, and N records in the child table) in a simple way without doing any loop to set the FK ? 
What is the better way to do it please ?

  Discussion posts and replies are publicly visible

Parents
  • 0
    Certified Lead Developer

    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.

Reply
  • 0
    Certified Lead Developer

    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.

Children
  • 0
    Certified Senior Developer
    in reply to Mike Schmitt

    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) ? 

  • 0
    Certified Lead Developer
    in reply to cedric01

    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.

  • 0
    Certified Lead Developer
    in reply to Dave Lewis

    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.

  • 0
    Certified Senior Developer
    in reply to Mike Schmitt

    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 ?

  • 0
    Certified Lead Developer
    in reply to cedric01

    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.

  • 0
    Certified Lead Developer
    in reply to Chris

    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 :) 

  • 0
    Appian Employee
    in reply to Chris

    I don't see makerange() as a function in my instance of Appian - I would guess that it is probably from a plugin.

  • 0
    Certified Senior Developer
    in reply to Peter Lewis

    Thanks a lot for your replies.
    It will give me some new ideas for my next processes.