Microsoft Dynamics 365 has different Activity entities, showing actions from the CRM users. ActivityPointer records are automatically created when an Activity record is created, enabling developer to retrieve different Activity types with one request.
If you don’t understand how to use the ActivityPointer record you can quickly get bogged down trying to retrieve individual Activity types.
Dynamics developers should think in entities when designing solutions, activities track the activity and effort of the people using the CRM Solution.
Activities are the actions users do in Dynamics, often tracking the interaction between users and customers.
Dynamics has lots of different activities
- Custom Activities
Tracking the activity of users/customers, records the time spent on records. For cases, you can see activities associated with the case. Tracking activities allows different people to work a record with a full knowledge of the status of the case.
- Activity is an entity in Dynamics 365, you can look at it in the custom solution
- The activity entity is non-editable.
- Activity schema name is ActivityPointer e.g ActivityPointer = Activity
- ActivityPointer is not the same as Activity Party
Microsoft ActivityPointer description
“Task performed, or to be performed, by a user. An activity is any action for which an entry can be made on a calendar.”
What’s the purpose of the Activity Entity?
If you can’t explain it simply, you don’t understand it well enough.
To understand the functionality, you need to understand its purpose. Once you understand what it’s used for, how it works and why it works in that way.
Dynamics developers Why Dynamics Developers should always start with the SDK/Web API and then explain it to yourself in your own words.
The purpose of the Activity entity is in the schema name — ActivityPointer. Developers can retrieve all activities with one request, instead of multiple retrieves using the different activity types.
The activity views allow you to show all activities for a record, despite the activities being different types (e.g. Email, PhoneCall, Task)
The Dynamics SDK/Web API has a great page on Activity entities.
The diagram shows why understanding Activities is important, Activities are linked to the primary entities in Dynamics. Activity entity acts like an interface between primary entities and individual activities.
Why do you need to know ActivityPointer?
ActivityPointer is a generic, it holds links to all activities. You gain the ability to retrieve all Activities but lose the ability to retrieve individual fields or custom fields on the different Activities.
The alternative would be to have a Sub-grid for each different activity type!
The ActivityPointer is a wrapper or interface to all activities, it includes the generic fields found on all activities. Microsoft ensures activities have common fields by making you tick the activity checkbox when creating an activity entity.
ActivityPointer.ActivityId will have the same value as the Activity its wrapping. Using the example of an Email activity.
Email.ActivityId will have the same value as the ActivityPointer.ActivityId
Doing an advanced find for Activities, when you click on an Activity record it will open the Activity, e.g. click on Activity record of type email, it will open the email.
ActivityId’s are the same because an Activity record is created by Dynamics when an activity record (Task/PhoneCall/Email/etc) is created.
Doing an advanced find, you can use the Activity Type field on the ActivityPointer entity to see what Activites types can be ActivityPointer records. The Activity Type is a Global option set
There are lots of activity types which don’t look like regular activities, such as
- Bulk Operation
- Case Resolution
- Opportunity Close
CRM creates activities when a Case/Opportunity is closed but why don’t these activities appear in the Activity views?
The field IsRegularActivity on the ActivityPointer entity is set to no for Dynamics activities.
If you search for all Activities you can view the non-regular activities, I mainly had Case Resolutions
When creating a custom entity you can specify if the entity is an activity by checking Define as an Activity entity
I have discussed this in detail in this blog post below
Think about the security limitations of creating Custom Activities, e.g. Any security settings will be applied to all activities. It’s unlikely you want any security on activities because most users need to read and create activities.
Important facts to remember when creating Custom Activities
- Custom Entities when created by default are not viewable/usable to any users apart from System Administrator and System customizer roles. Other security roles will have to add the entity (don’t forget)
- If an entity is selected as an Activity this cannot be undone
- Custom Activity entities are available to users who have access to other Activityentities
I have worked on a project where security concerns meant the custom Activity was converted to a standard entity. We created a custom entity (Which you can apply security too), copied the data into your new entity, deleting the custom Activity.
Activity and SQL
ActivityPointer entity has an SQL table and Filtered view () created on the CRM database.
- Table — ActivityPointerBase
- Filter — ActivityPointer
Tables in the CRM database allows you to create reports using Activities. Best practise is to use the ActivityPointer filter, why filtered views are useful
The blog post does an excellent job explaining Activity entity with SQL.
Activity coding problem
I needed to reactivate a case and reactivate the last Activity for the case.
The existing code activated Tasks but now I needed to activate Tasks and PhoneCalls.
Developer assumptions cause many bugs. Functionality should work how the user wants it to work, not the developer, remember You are not the end user
I needed to check all the activities for the case and reactivate the last PhoneCall or Task activity. Task and PhoneCall had a custom field which indicated if the Activity should be reactivated.
The custom field increased the complexity, ActivityPointer record doesn’t contain the custom field because ActivityPointer contains generic fields common on all Activityrecords.
- Retrieve all the Activities using ActivityPointer
- Loop through Activities, checking if the Activity was of type PhoneCall or Task
- Use Activity.ActivityId to retrieve the Activity
Here is Linq query I used to retrieve ActivityPointer
After writing this post, there is a simpler solution. I retrieved all the Activities and had to loop through the list, discarding activities until I got to a Task or PhoneCall.
I could have used the ActivityType filter to retrieve the ActivityPointer records with an ActivityType of PhoneCall and Task.
picture from here