CRM 2015 – What developers need to know about the activity entity

Microsoft Dynamics CRM 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.

CRM developers should think in entities when designing CRM solutions, activities track the activity and effort of the people using the CRM Solution.

Activities are the actions users do in CRM, often tracking the interaction between users and customers.

CRM has lots of different activities

  • PhoneCall
  • Task
  • Letter
  • Email
  • Appointment
  • Fax
  • Custom Activities

Tracking the activity of users/customers, records the time spent on CRM 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 facts

  1. Activity is an entity in CRM, you can look at it in the custom solution
  2. The activity entity is non-editable.
  3. Activity schema name is ActivityPointer e.g ActivityPointer = Activity
  4. 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.

Albert Einstein

To understand a CRM 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.

CRM developers should Start with the CRM SDK 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 CRM SDK has a great page on Activity entities.

The diagram shows why understanding Activities is important, Activities are linked to the primary entities in CRM.  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!

activitypointer views

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

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

activitypointer view

activity pointer email fetchxml

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 CRM when an activity record (Task/PhoneCall/Email/etc) is created.

Activity Types

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

activity type

Activity Type – activitypointer_activitytypecode

activity type 1

IsRegularActivity?

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 CRM created Activities.

If you search for all Activities you can view the non-regular activities, I mainly had Case Resolutions

activitypointer

Custom Activities

When creating a custom entity you can specify if the entity is an activity by checking Define as an Activity entity

activity checkbox

I have discussed this in detail in this blog post below

CRM 2013 – When should you create a custom activity entity?

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 Activity entities

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.

All About Activity Entity Query Full Guidance in CRM 2011/2013 : Basic–Complex (ActivityPointer, ActivityParty) Queries in One Post

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 Activity records.

My plan

  • 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


        public List<ActivityPointer> GetRecentActivityForIncident(Guid incidentId)
        {
            
            this.tracingService.Trace("Enter Method GetMostRecenActivityForIncident");
            using (OrganizationServiceContext crmContext = new OrganizationServiceContext(this.crmService))
            {
                var mostRecentWrappedTask = (from t in crmContext.CreateQuery<ActivityPointer>()
                    where
                        (t.RegardingObjectId != null && t.RegardingObjectId.Id.Equals(incidentId))
                        && ((int) t.StateCode.Value == (int) TaskState.Completed)
                    orderby t.CreatedOn descending
                    select t);
                return mostRecentWrappedTask.ToList();
            }

        }

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.

 

 

 

13 thoughts on “CRM 2015 – What developers need to know about the activity entity

  1. Cyno November 24, 2015 / 11:38 am

    Awesome Hosk you have done a great job!

    Since a long time i am having problem with Activity coding problem and when today when i read this article after that i felt that it’s too simple but my mind is not thinking beyond.

    Thanks Hosk for such a nice post it is really helped me.

    Like

    • Hosk November 24, 2015 / 12:27 pm

      Glad it helped you understand activities

      Like

  2. Jeremy January 25, 2016 / 9:46 pm

    Hi Hosk. How would you approach the problem of preventing all activities from being created which relate to an accounts service type of a specific value. So for example, if I create any type of activity which relates to an account which has a service type of X, then on create – do something like throw InvalidPluginExecution or delete created record etc.

    Is there a general way to target all activities in a plug-in or would I have to go a custom workflow acitivity route?

    Like

    • Hosk January 25, 2016 / 10:08 pm

      2 ways to solve the problem I can think of

      1. Create a plugin to stop certain activities being created. You could throw an InvalidPlugException, this would allow you to show a message to the user to tell them an activity won’t be created

      2. Delete the activity after creation using either a workflow or plugin.

      The plugin would allow you to create criteria to select certain plugins and it would trigger as soon as the activity was created. The downside is it will run when any activity is created

      Like

  3. Sudha October 4, 2016 / 10:35 am

    Hi Hosk, In case form, i am showing the activity as subgrid. There i want to display the email direction code. Is it possible?

    Like

  4. Jeff O August 11, 2017 / 1:40 am

    Hosk, are direct updates to the activityPointerBase from code supported?

    Like

    • Hosk August 11, 2017 / 9:06 am

      I don’t know. If you can do it with the SDK it’s supported

      Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.