August 28, 2014

CRM plugins. The proper way of updating values of records in context.

In this post I will try to describe how to properly, inside a plugin, change attribute values of the record that triggered the create or update operation. From time to time I stumble upon code that threats the context record (the one on which a create or update operation triggered a plugin) as any other record, which is wrong.

How it should not be done:

  1. A plugin step is registered on the create event of entity E.
  2. Record A of entity E is created.
  3. The registered create plugin step fires.
  4. (…) Some business logic (…)
  5. Record A is updated by calling the organization service .Update() method.

Or even worse:

  1. A plugin step is registered on the update vent of entity E.
  2. Record A of entity E is updated.
  3. The registered update plugin step fires.
  4. (…) Some business logic (…)
  5. Record A is updated by calling the organization service .Update() method.
  6. The registered update plugin step fires again (since an update was done).
  7. Inside the plugin the .Depth property of the execution context is checked to avoid infinite loops.

What is wrong in both these scenarios is that an Update request is used to update the context record. This causes:

  1. Unnecessary load on the CRM application and database.
  2. Infinite loops in plugins.
  3. Possible transactional  errors and performance issues, which could lead to plugins failing.

The above approach might be used by analogy with SQL databases. But the CRM service is not a SQL database, and requires a different approach.

The proper way of doing this is registering the plugin step (create or update) in the pre event inside transaction phase (20) and modifying the attributes directly in the target entity. All changes done to entity attributes in the “20” phase will be stored, without any unnecessary round trips and service calls.

image

This is a simple example showing a plugin that sets new_attribute3 to a string concatenation of new_attribute1 and new_attribute2. It is of course simplified, does not check validate the values, check for nulls, etc. but it proves the point.

If this code is registered to execute on the pre operation (20) phase, the value of new_attribute3 will be updated, without any other operations. This is because when in phase 20 it modifies the record before CRM does the core database operation (30). So anything we change here, will be what gets later pushed to SQL.