Alan Judi
Alan Judi

Reputation: 1112

Why won't records delete?

I wrote a plugin that gets the GUID IDs through fetchXML and uses Batch delete to delete the records in batches of 1000.

I debugged the plugin and it shows that the plugin executes all the way through to service.RetrieveMultiple(new FetchExpression(fetchxml)), however, the fetched records are not getting deleted. Can someone explain why? Here is the plugin code:

using System;
using System.Linq;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Query;


/// <summary>
/// This plugin will trimm off unit orders after a contract is cancelled before the end of the contract duration
/// </summary>

namespace DCWIMS.Plugins
{

    [CrmPluginRegistration(MessageNameEnum.Update,
    "contract",
    StageEnum.PostOperation,
    ExecutionModeEnum.Asynchronous,
    "statecode",
    "Post-Update On Cancel Contract",
    1000,
    IsolationModeEnum.Sandbox,
    Image1Name = "PreImage",
    Image1Type = ImageTypeEnum.PreImage,
    Image1Attributes = "")]

    public class UnitPluginOnCancel : IPlugin
    {

        public void Execute(IServiceProvider serviceProvider)
        {
            // Extract the tracing service for use in debugging sandboxed plug-ins.
            // Will be registering this plugin, thus will need to add tracing service related code.

            ITracingService tracing = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            //obtain execution context from service provider.
            IPluginExecutionContext context = (IPluginExecutionContext)
                serviceProvider.GetService(typeof(IPluginExecutionContext));

            // Output Parameters collection contains all the data passed in the message request. 

            if (context.InputParameters.Contains("Target") &&
                context.InputParameters["Target"] is Entity)
            {

                Entity entity = (Entity)context.InputParameters["Target"];

                //Get the before image of the updated contract
                Entity PreImage = context.PreEntityImages["PreImage"];


                //verify that target entity is contract and contains a cancellation date
                if (entity.LogicalName != "contract" || entity.GetAttributeValue<OptionSetValue>("statecode").Value != 4)
                    return;

                if (PreImage.GetAttributeValue<OptionSetValue>("statecode").Value == 0 || entity.Contains("cancelon"))
                    return;

                if (PreImage.GetAttributeValue<OptionSetValue>("statecode").Value == 3 || PreImage.GetAttributeValue<OptionSetValue>("statecode").Value == 1)
                    return;

                //obtain the organization service for web service calls.
                IOrganizationServiceFactory serviceFactory =
                    (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);


                //Core Plugin code in Try Block
                try
                {

                    //Get Contract line start date
                    var startDate = PreImage.GetAttributeValue<DateTime>("cancelon");

                    //Get Contract Line End Date
                    DateTime endDate = (DateTime)PreImage["expireson"];

                    //Get Contract range into weekdays list
                    Eachday range = new Eachday();
                    var weekdays = range.WeekDay(startDate, endDate);

                    //Get Unit Order Lookup Id
                    EntityReference unitOrder = (EntityReference)PreImage.Attributes["new_unitorderid"];

                    var unitOrders = service.Retrieve(unitOrder.LogicalName, unitOrder.Id, new ColumnSet("new_name"));
                    var unitOrdersId = unitOrders.Id;

                    var uiName = unitOrders.GetAttributeValue<string>("new_name");

                    //Get Entity Collection to delete 

                    string fetchXml = @" <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false' top='2000'>
                        <entity name='new_units'>
                            <link-entity name='new_alterunitorder' from ='new_orderlineid' to = 'new_unitsid' >
                                <attribute name='new_alterunitorderid' />
                                <filter type='and'>
                                    <condition attribute='new_orderdate' operator='on-or-after' value='" + startDate.ToString("yyyy-MM-dd") + @"' />
                                    <condition attribute='new_orderdate' operator='on-or-before' value='" + endDate.ToString("yyyy-MM-dd") + @"' />
                                    <condition attribute='new_orderlineid' operator='eq' uiname='" + uiName + @"' uitype='new_units' value='" + unitOrdersId + @"' />
                                </filter>
                            </link-entity>
                        </entity>
                    </fetch>";


                    var result = service.RetrieveMultiple(new FetchExpression(fetchXml));

                    var entityRefs = result.Entities.Select(e => e.GetAttributeValue<EntityReference>("new_alterunitorderid"));


                    var batchSize = 1000;
                    var batchNum = 0;
                    var numDeleted = 0;

                    while (numDeleted < entityRefs.Count())
                    {
                        var multiReq = new ExecuteMultipleRequest()
                        {
                            Settings = new ExecuteMultipleSettings()
                            {
                                ContinueOnError = false,
                                ReturnResponses = false
                            },
                            Requests = new OrganizationRequestCollection()
                        };

                        var currentList = entityRefs.Skip(batchSize * batchNum).Take(batchSize).ToList();

                        currentList.ForEach(r => multiReq.Requests.Add(new DeleteRequest { Target = r }));

                        service.Execute(multiReq);

                        numDeleted += currentList.Count;
                        batchNum++;
                    }


                }
                catch (FaultException<OrganizationServiceFault> ex)
                {
                    throw new InvalidPluginExecutionException("An error occured.. Phil is responsible. ", ex);
                }
                catch (Exception ex)
                {
                    tracing.Trace("An error occured: {0}", ex.ToString());
                    throw;
                }
            }


        }

    }

}

I tried this:

var entityGuids = result.Entities.Select(ent => ent.GetAttributeValue<Guid>("new_alterunitorderid"));
var entityRefs = entityGuids.Select(guid => new EntityReference("new_alterunitorder", guid));

Got this:

guids are not being retrieved

Upvotes: 1

Views: 411

Answers (2)

Nick
Nick

Reputation: 755

Usually batch jobs are asynchronous. Go in Settings > System Jobs. Search for your delete job. I never used this specific syntax but the logic seems ok.

Upvotes: 1

jasonscript
jasonscript

Reputation: 6178

I think the error is immediately after you execute the RetrieveMultiple request

var entityRefs = result.Entities.Select(e => e.GetAttributeValue<EntityReference>("new_alterunitorderid"));

new_alterunitorderid is not an EntityReference. It is a primary key.

Instead try:

var entityRefs = result.Entities.Select(e => e.ToEntityReference());

You should also make use of your tracing object to include more output in your trace logs:

 tracing.Trace("Executing query");
 var result = service.RetrieveMultiple(new FetchExpression(fetchXml));
 tracing.Trace("{0} results found. Converting to EntityReferences", result.Entities.Count);
 var entityRefs = result.Entities.Select(e => e.ToEntityReference());

Upvotes: 2

Related Questions