Search code examples
pluginsdynamics-crmmicrosoft-dynamics

Obtain and use Reference from a related record in Dynamics 365 Plugin


I am trying to write a simple plugin that triggers on Update of a child record and calculates a money field from all child records into the parent.

I have tried everything and managed to get it to work when triggered from random field in the account, but not the other way.

The error I get is the below, even if all the fields are 100% correctly spelled and not empty. The full execution code is below:

Exception Message: The given key was not present in the dictionary.
ErrorCode: -2147220956
HexErrorCode: 0x80040224
using System;
using System.Linq;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;

namespace MyPlugin
{
    public class SumRelatedProducts : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {

            // Obtain the execution context from the service provider.
            IPluginExecutionContext context = (IPluginExecutionContext)
                serviceProvider.GetService(typeof(IPluginExecutionContext));
            if (context.Depth > 1)
            {
                return;
            }

            // Obtain the product from the input parameters.
            Entity product = (Entity)context.InputParameters["Target"];
          

            // Obtain the organization service reference.
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            // Retrieve the related entity

            EntityReference relatedEntityRef = (EntityReference)product.Attributes["sen_accountid"];
            Entity account = service.Retrieve(relatedEntityRef.LogicalName, relatedEntityRef.Id, new ColumnSet(true));

            // Create a new organization service context.
            var orgContext = new OrganizationServiceContext(service);

            // Sum up the related products using an arrow function.
            decimal sum = 0m;
            var relatedProductEntities = orgContext.CreateQuery("sen_productmatrix")
                .Where(a => ((EntityReference)a["sen_accountid"]).Id == relatedEntityRef.Id)
                .ToList();
            sum = relatedProductEntities.Sum(productEntity => ((Money)productEntity["sen_rev"]).Value);

            // Update the sum on the account entity.
            account["sen_sum"] = new Money(sum);
            service.Update(account);
        }
    }
}

Logical and schema name of the lookup field Visual presentation of the subgrid with records

I have tried adding all sort of validations and in the case below it throws an exception which is even more confusing since clearly the field exists, not empty and the record is saved.

if (product.Attributes.ContainsKey("sen_accountid"))
{
    // Retrieve the related record
    EntityReference acc = (EntityReference)product.Attributes["sen_accountid"];
    Entity retrievedRecord = service.Retrieve("account", acc.Id, new ColumnSet(true));
(...)

Solution

  • You did not share a stack trace, but I guess the error occurs on this line:

    EntityReference relatedEntityRef = (EntityReference)product.Attributes["sen_accountid"];
    

    In the plugin pipeline handling the update message the entity passed as "Target" in the IPluginExecutionContext.InputParameters collection only holds the attributes that have been modified. Other attributes needed to process the update must be derived from an entity pre (or post) image.

    Register an entity image for your plugin step holding attribute sen_accountid.

    In your plugin you can get the ID of the related account record using this code:

    EntityReference relatedEntityRef = context.PreEntityImages
        .First()
        .Value
        .GetAttributeValue<EntityReference>("sen_accountid");