Dynamically Populate Polymorphic Lookup Value in Power Automate without using Condition Step
In my previous post, I have described how to
populate Owner value dynamically in Power Automate. The trick I used in that post only works for the Owner lookup though and not for polymorphic lookups. And the reason why is because if you are using the Dataverse/Common Data Service (current environment) connector, there is only one input parameter for the Owner column unlike for polymorphic lookups where there can be multiple input parameters (one for each possible table type).
In this post, I will explain how you can dynamically populate a polymorphic lookup column by setting the "Entity name" parameter with an expression value and set the column values with a JSON object in "Record Item" parameter. Let’s have a look at scenarios where we can use this trick.
Scenario 1: Clone a Case and populate the Customer lookup (which can be an Account or Contact) with the original case’s Customer value.
You'd thought you can just populate the respective columns for each type but you cannot simply populate the Customer lookup as in the screenshot
below. The value will be of only one table type for each case and the create
action will always fail with the error below.
{Table Name} With Id = xxxxxx Does Not Exist
Scenario 2: Create a follow-up task for the email and populate the
Regarding column with the same Regarding value from the email.
The Regarding value can be Account, Contact, Case or other
table types.
Scenario 3: When a Case row is cloned, all the related
Connections need to be cloned. The case can be connected to any table
type in the system (Account, Contact, Case or other custom tables).
Now let’s use the trick in the scenarios I mentioned above.
Update Polymorphic Lookup Value
The trick to updating polymorphic lookups easily is to create a row (e.g. task, connection) without the value for the polymorphic lookup first, and then update the row to set the value for it later on.
🛈 Note
The Power Automate Experimental Features are enabled for the account that I use to build this flow, so the expression builder in the screenshots of this post is different from the classic one. You can either follow this blog post to enable Experimental Features in your Power Automate settings or you will have to figure out the equivalent option in the classic expression builder.
The Power Automate Experimental Features are enabled for the account that I use to build this flow, so the expression builder in the screenshots of this post is different from the classic one. You can either follow this blog post to enable Experimental Features in your Power Automate settings or you will have to figure out the equivalent option in the classic expression builder.
The steps below address Scenario #2 above and describes how to set the Regarding Lookup.
The first step is pretty straight forward. List the Emails based on certain
filter criteria and create a new Task for each Email and
leave the Regarding column empty.Note that the value to be entered here as custom value is EntitySetName (not logical name) which is the plural/collection version of the logical name (e.g. tasks). You can find out more detail for this in this post.
To make sure that the step is rendered as a generic step, use a string
function in the expression builder (e.g. trim('tasks') ) and the end
result should be something like this screenshot with "Record Item"
parameter and no column parameter from the table.
The Record Item parameter accepts the column name and values as a JSON
object. This is the sample Record Item parameter value to set the Regarding column with one of the Accounts using hardcoded GUID.
{
"regardingobjectid_account_task@odata.bind": "accounts(6e060750-ab16-eb11-a812-000d3a6aa8dc)"
}
The value has x3 parts which can vary depending on the Regarding value of the original record.
- Single-valued navigation property (e.g. regardingobjectid_account_task)
- EntitySetName (e.g. accounts)
- Row GUID (e.g. 6e060750-ab16-eb11-a812-000d3a6aa8dc)
To make the values dynamically populate from the Regarding value of the Email, replace the following:
- part of the single-valued navigation property with the logical name of the Regarding (Type)
- EntitySetName needs to be built using an expression (more details below)
- Regarding (Value) can be used for GUID
EntitySetName is not returned as part of the "Get a record" or "List records" actions and it cannot be easily derived from the logical name. Not all of the EntitySetName are properly suffixed plural version of the logical name. One of the options is to write an expression and return the correct EntitySetName based on the logical name (e.g. If logical name = "account", use "accounts", else if logical name = "contact", use "contacts", else if logical name = "incident", use "incidents").
if
(
equals
(
items('Apply_to_each_Email')?['_regardingobjectid_value@Microsoft.Dynamics.CRM.lookuplogicalname'],
'account'
),
'accounts',
if
(
equals
(
items('Apply_to_each_Email')?['_regardingobjectid_value@Microsoft.Dynamics.CRM.lookuplogicalname'],
'contact'
),
'contacts',
if
(
equals
(
items('Apply_to_each_Email')?['_regardingobjectid_value@Microsoft.Dynamics.CRM.lookuplogicalname'],
'incident'
),
'incidents',
'ERROR'
)
)
)
The expression will be a lot longer if you need to cater to more table types. This "Update a Record" step will dynamically populate the Regarding value without having to branch out with multiple condition steps. It is the same approach for the Customer lookup column but there will be only two types of tables (Account and Contact).
Create Row with Polymorphic Lookup Value
If you are proficient in JSON and expression, you can apply the same approach for the "Create a record" step by populating all column values to Record Item parameter with a JSON object. In that way, you can save one API call for not having to update the polymorphic lookup value with an additional step. You can also copy the JSON object parameters from the "Create a Record" step by clicking on the "Peek code" menu item, copy the parameters starting with "item/" and replace "item/" from the parameter name.
Here is how the final "Create a record" step with JSON parameter will look like.
Create Connection with Dynamic Connected To Lookup Value
The following flow is for Scenario 3 to clone the Connections related to the Case and link with the new Case. The Connected To value can be Account, Contact or Case.
Similar to the Regarding lookup scenario, the Connection can be created by setting the value of Connected To lookup dynamically using the following JSON.
{
"record1id_@{items('Apply_to_each_Connection')?['_record1id_value@Microsoft.Dynamics.CRM.lookuplogicalname']}@odata.bind": "incidents(@{variables('New Case ID')})",
"record2id_@{items('Apply_to_each_Connection')?['_record2id_value@Microsoft.Dynamics.CRM.lookuplogicalname']}@odata.bind": "@{if
(
equals
(
items('Apply_to_each_Connection')?['_record2id_value@Microsoft.Dynamics.CRM.lookuplogicalname'],
'account'
),
'accounts',
if
(
equals
(
items('Apply_to_each_Connection')?['_record2id_value@Microsoft.Dynamics.CRM.lookuplogicalname'],
'contact'
),
'contacts',
if
(
equals
(
items('Apply_to_each_Connection')?['_record2id_value@Microsoft.Dynamics.CRM.lookuplogicalname'],
'incident'
),
'incidents',
'ERROR'
)
)
)}(@{items('Apply_to_each_Connection')?['_record2id_value']})",
"record1roleid@odata.bind": "@{if(
empty(items('Apply_to_each_Connection')?['_record1roleid_value']),
'',
concat(
'connectionroles(',
items('Apply_to_each_Connection')?['_record1roleid_value'],
')'
)
)}",
"record2roleid@odata.bind": "@{if(
empty(items('Apply_to_each_Connection')?['_record2roleid_value']),
'',
concat(
'connectionroles(',
items('Apply_to_each_Connection')?['_record2roleid_value'],
')'
)
)}"
}
Sometimes, the input parameters for certain action steps are not rendered properly in the flow designer. E.g. If the WinQuote action is selected in the Perform an unbound action step, it shows some columns from the Quote Close Activity instead of one single QuoteClose parameter as specified in the documentation. (probably because the flow designer is not able to render the QuoteClose object type properly)
- QuoteClose: JSON object with column values for Quote Close Activity
- Status: 4 (for Won statuscode)
{
"QuoteClose": {
"subject": "Quote Won (Won) - @{outputs('Get_a_record')?['body/quotenumber']}",
"category": 1,
"quoteid@odata.bind": "quotes(@{outputs('Get_a_record')?['body/quoteid']})",
"quotenumber": "@{outputs('Get_a_record')?['body/quotenumber']}",
"revision": @{outputs('Get_a_record')?['body/revisionnumber']},
"statuscode": 2
},
"Status": 4
}
You can find out more details in my next post on how to perform bound/unbound action with EntityType parameters.
Summary
By setting the "Entity name" parameter with an expression value which is not recognisable by the flow designer, the input parameters of Create/Update actions of Dataverse/CDS (current environment) connector change from the column names to one single "Record Item" JSON object parameter. For "Record Item" JSON object, you can specify the entity name of the lookup value dynamically using an expression to populate the polymorphic lookups dynamically. There are also many other things that you can achieve with this generic Create/Update step with "Record Item" parameter such as
- Creating multiple types of table dynamically with one single step (e.g. create different types of activities conditionally) by providing the "Entity name" with expression
- Populating different number of columns dynamically by add/removeProperty of JSON object based on the condition
Stay tuned for my next post where I will explain how to dynamically set the array item value of the table (e.g. Activity Parties of Activity/Email/Task table) with JSON object array.
Amazing work!!! Thank you so much for this. This saved me a lot of frustration and possibly creating the Close Quote activity manually because of the _quoteid_value field in the unbound action!! I can't thank you enough. :)
ReplyDeleteI am glad that my blog post helped you solved the problem. 😊
Delete