Search code examples
c#.netdynamics-crm-2011dynamics-crm-2016

Retrieve triggering an update in plugin


I've got a plugin on Update (pre-op) of InvoiceDetail, in which I'm retrieving the associated Invoice to get some more information from it (ie: the tax profile that was selected at the invoice level) in CRM 2016.

Here's how I do it:

//xrmObjects is an object containing all useful objects in plugins/workflow...
var invoice = RetrieveEntity(xrmObjects.Service, xrmObjects.TracingService, image["invoiceid"] as EntityReference, new ColumnSet("invoiceid", "pricelevelid", "customerid", "opportunityid", "xtc_tax_definition"));

This specific line of code above triggers another Update on InvoiceDetail

Here's the method invoked above:

public static Entity RetrieveEntity(IOrganizationService service, ITracingService tracingService, EntityReference target, ColumnSet columnSet)
{

    Entity entity = new Entity();

    try
    {
        entity = CrmServiceExtensions.ExecuteWithRetry<RetrieveResponse>(service, new RetrieveRequest
        {
            Target = target,
            ColumnSet = columnSet

        }).Entity;
    }
    catch (Exception ex)
    {
       tracingService.Trace($"Error retrieving {target.LogicalName}: {ex.Message}");
       throw;
    }

    return entity;

}

Here's ExecuteWithRetry:

public static T ExecuteWithRetry<T>(IOrganizationService service, OrganizationRequest request)
            where T : OrganizationResponse
        {
            T response = null;
            int i = 0;

            // Maximum of five iterations.
            while (i < 5)
            {
                try
                {
                    response = (T)service.Execute(request);

                    // If the Execute does not throw an Exception, break the loop
                    break;
                }
                catch (System.Web.Services.Protocols.SoapException e)
                {
                    // Retry if the SoapException is a "Generic SQL Error",
                    // otherwise rethrow the SoapException.
                    // "Generic SQL Error" might indicate a deadlock.
                    if (e.Detail.InnerText.ToLower().Contains("generic sql error"))
                    {
                        ++i;
                        // Wait (sleep thread) for i * 1000 milliseconds.
                        // So, first iteration waits 1 second,
                        // while fifth iteration will wait 5 seconds.
                        System.Threading.Thread.Sleep(i * 1000);
                    }
                    else throw;
                }
            }

            if (i >= 5)
            {
                throw new Exception("ExecuteWithRetry: too many retries");
            }

            return response;
        }

I have validated that nothing funky is happening, the update message on InvoiceDetail is triggered again at the line response = (T)service.Execute(request);

I also tried by using early-bound and a context to retrieve the invoice but the LoadProperty methods which loads the invoice does the same thing....

using (XrmServiceContext ctx = new XrmServiceContext(xrmObjects.Service))
{

    Xrm.InvoiceDetail image = xrmObjects.PluginContext.PreEntityImages["invoicedetail"].ToEntity<Xrm.InvoiceDetail>();

    try
    {
        ctx.LoadProperty(image, "invoice_details");
    }
    catch (Exception ex)
    {
        throw new InvalidPluginExecutionException($"Error retrieving invoice details' invoice: {ex.Message}");
    }

}

I can't see anything in my steps configuration that would do this. Any ideas?


Solution

  • Instead of using LoadProperty, I simply retrieved the invoice manually like so

    var invoice = ctx.InvoiceSet.SingleOrDefault(x => x.Id == image.InvoiceId.Id);
    

    Instead of:

    ctx.LoadProperty(image, "invoice_details");
    

    For some reason, LoadProperty is triggering unwanted update message on child invoice details...