Activity entities within the Common Data Service / Dynamics 365 have traditionally been…problematic at the best of times. While an entirely useful construct when working from a functional standpoint in the application, their backend structure can cause some challenges when evaluating more technical requirements. A lot of this comes down to their unique characteristics. For example, all default and custom activity records have a relationship behind the scenes to the activitypointer entity which, in effect, acts as a common table within the backend SQL Server database to record all activity records created in the system. An additional complication also arises when you start associating activities to other, related records in the system. As an example, consider the Appointment entity’s Required Attendees and Optional Attendee fields. Users can populate this with potentially many different types of records in the system - a Contact, Account or even a custom entity. Attempting to, therefore, work programmatically with these fields can introduce some additional complexity and make it more challenging to achieve your particular requirement.
A recent example I was working with highlights well some of the difficulties Activity entities can bring to the table and, in this specific circumstance, the issue involves the Task entity specifically. I was building out a canvas Power App to handle the creation and assignment of tasks into CDS. The first of these was pretty straightforward - I simply built out a collection of Task records within a specific area of the application and then patched each of these iteratively into the Common Data Service database. In essence, the formula I used resembled the below, which in this instance, would create a single Task record within the database:
Patch(Tasks, Defaults(Tasks), {subject: “My New Task”, prioritycode: ‘Priority (Tasks)’.Normal})
I’m using the logical names of each field, more out of force of habit than anything else. The following formula would also be valid and achieve the same result:
Patch(Tasks, Defaults(Tasks), {Subject: “My New Task”, Priority: ‘Priority (Tasks)’.Normal});
So far, so good. The next stage was to determine whether I could also assign the task on creation to another user. Say, for example, I wanted to assign a Task to me upon record creation:
Patch(Tasks, Defaults(Tasks), {subject: “My New Task”, prioritycode: ‘Priority (Tasks)’.Normal, ownerid: LookUp(Users, fullname = “Joe Griffin”)})
In this circumstance, we start to hit a problem - for some reason, the Common Data Service connector cannot write to this field and instead produces the following error:
What’s most frustrating about this is that this issue seems to have crept in as part of some recent updates to the Common Data Service connector within Power Apps. The benefits of this update have been immense, in allowing us to work more effectively with Option Set fields and polymorphic fields, but it seems to have broken this specific field in the process.
To find a solution, so we can successfully assign Tasks to our desired Owner from within the canvas app, we must instead turn to Microsoft Power Automate flows. We have had the longstanding capability to trigger flows at specific action points, so this solution - while not necessarily being the “nicest” one at our disposal - can be leveraged to help address the requirement. We start by building a flow that resembles the below:
We use the Power Apps trigger action and, from there, prompt for two specific pieces of information - the ID of the Task record to update and then the ID for the User we wish to reassign the record to and then the Owner Type field - in this case, we set it to systemusers. In this specific scenario, we only expect Tasks ever to be assigned to a User record, not a Team. You could adjust the Flow to accept an additional parameter, which you can then evaluate to set the Owner Type field to the correct value.
With the flow built out, we can then look to add it into our canvas app and then use the following formula to perform the reassignment, where AssignTaskstoCorrectOwner is the name of our Power Automate flow and the parameters fed to the flow contain the generated activityid from the previous step and the ID of the user to re-assign the record to:
ClearCollect(newTask, Patch(Tasks, Defaults(Tasks), {subject: “My New Task”, prioritycode: ‘Priority (Tasks)’.Normal})); ForAll(newTask, AssignTaskstoCorrectOwner.Run(activityid, userID));
In this specific example, we are only patching a single Task record. To patch multiple records within a collection called myTasks, you would adjust the first line of the above code as follows:
ClearCollect(newTask, ForAll(myTasks, Patch(Tasks, Defaults(Tasks), {subject: “My New Task”, prioritycode: ‘Priority (Tasks)’.Normal})));
Now, Power Apps will trigger the above flow each time you create a Task record, to ensure you can reassign the record to its correct Owner 🙂
It’s a little bit annoying that something that used to work without issue now becomes something that we have to find a workaround to resolve. However, we shouldn’t complain really. The improvements made to the Common Data Service connector have been immensely helpful in other areas, allowing non-technical users to work more efficiently with complex data types that have long plagued seasoned Dynamics CRM / 365 developers. It’s just a relief that Power Automate can step in to fill the gap and achieve a solution that not only works but is relatively simple to implement too.