Skip to main content

Notifications

Customer experience | Sales, Customer Insights,...
Answered

Two Identical Delete Plugins | One works, one doesn't

Posted on by 40

Hi experts,

 

I have a issue on my delete plugins. I have 2 delete plugins. Both are identical.

  • Delete of ExtraCost
  • Delete of Duration

 2022_2D00_01_2D00_13-11_5F00_15_5F00_10_2D00_Plugin-Registration-Tool.png

2022_2D00_01_2D00_13-11_5F00_12_5F00_15_2D00_.png2022_2D00_01_2D00_13-11_5F00_12_5F00_26_2D00_.png

As you can see both are identical. Both having the same pre Image with the ID, TrainingID and Cost/Hours.

Both plugins also have the same code running. Only difference is that Extra Costs will update Remaining Budget and Duration will update Remaining Days.


Here's a code snippet of Extra Costs:

 

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.Linq;

namespace TrainingBudget.Plugin
{

    public class DeleteExtraCost : IPlugin
    {
        private static IOrganizationService _service;
        private IOrganizationServiceFactory _serviceFactory;
        private IPluginExecutionContext _context;

        public void Execute(IServiceProvider serviceProvider)

        {
            _context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            if (_context.Depth > 1)
            {
                return;
            }

            if (_context.MessageName != "Delete")
            {
                return;
            }
            _serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            _service = _serviceFactory.CreateOrganizationService(_context.UserId);

            UpdateBudgets();
        }
        private void UpdateBudgets()
        { 
                var extraKost = EntityMapper.Map(_context.PreEntityImages.FirstOrDefault(q => q.Key == "cref8_extrakost").Value);
                EntityReference extraKostERef = ((EntityReference)_context.PreEntityImages.FirstOrDefault(q => q.Key == "cref8_extrakost").Value.Attributes["cref8_extrakosttraining"]);
                var training = EntityMapper.Map(_service.Retrieve("cref8_opleiding", extraKostERef.Id, new ColumnSet("cref8_jaarstartopleiding")));

                var cursists = GetCursists("cref8_cursist", "cref8_extrakost_cref8_cursist", "cref8_cursistid", "cref8_extrakostid", training.Id);

                foreach (var cursist in cursists)
                {
                    var traineeBudget = GetTraineeBudget(cursist, training);

                    double nieuwBudget = traineeBudget.RemainingBudget   extraKost.Price;

                    Entity budget = new Entity("cref8_jaarlijkbudget");
                    budget["cref8_jaarlijkbudgetid"] = traineeBudget.Id;
                    budget["cref8_overigebudget"] = nieuwBudget;

                    _service.Update(budget);
                }
        }
        private static List GetCursists(string entityName, string linkToEntityName, string linkAttributeName, string attributeName, Guid id)
        {
            var query = new QueryExpression()
            {
                EntityName = entityName,
                ColumnSet = new ColumnSet("cref8_cursistid")
            };
            var link = query.AddLink(linkToEntityName, linkAttributeName, linkAttributeName);
            link.LinkCriteria = new FilterExpression()
            {
                Conditions =
                                    {
                                        new ConditionExpression(attributeName, ConditionOperator.Equal, id)
                                    }
            };

            return _service.RetrieveMultiple(query).Entities.Select(e => EntityMapper.Map(e)).ToList();
        }
        private static TraineeBudget GetTraineeBudget(Cursist cursist, Training training)
        {
            ConditionExpression ceYearlyBudgetFromTrainee = new ConditionExpression("cref8_cursist", ConditionOperator.Equal, cursist.Id);
            ConditionExpression ceYearlyBudgetYear = new ConditionExpression("cref8_jaar", ConditionOperator.Equal, (int)training.Year);
            FilterExpression filter = new FilterExpression();
            filter.Conditions.Add(ceYearlyBudgetFromTrainee);
            filter.Conditions.Add(ceYearlyBudgetYear);
            QueryExpression qeYearlyBudget = new QueryExpression("cref8_jaarlijkbudget");
            qeYearlyBudget.ColumnSet = new ColumnSet("cref8_jaarlijkbudgetid", "cref8_overigebudget");
            qeYearlyBudget.Criteria.AddFilter(filter);
            EntityCollection yearlyBudgetResult = _service.RetrieveMultiple(qeYearlyBudget);

            return EntityMapper.Map(yearlyBudgetResult.Entities.First());
        }

    }
}

 

Here's code snippet of Duration:

 

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Collections.Generic;
using System.Linq;

namespace TrainingBudget.Plugin
{
    public class DeleteDuration : IPlugin
    {
        private static IOrganizationService _service;
        private IOrganizationServiceFactory _serviceFactory;
        private IPluginExecutionContext _context;

        public void Execute(IServiceProvider serviceProvider)

        {
            _context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            if (_context.Depth > 1)
            {
                return;
            }

            if (_context.MessageName != "Delete")
            {
                return;
            }

            _serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            _service = _serviceFactory.CreateOrganizationService(_context.UserId);

            UpdateBudgets();
        }

        private void UpdateBudgets()
        {
            var duration = EntityMapper.Map(_context.PreEntityImages.FirstOrDefault(q => q.Key == "cref8_duratie").Value);
            EntityReference duratieERef = ((EntityReference)_context.PreEntityImages.FirstOrDefault(q => q.Key == "cref8_duratie").Value.Attributes["cref8_opleidingduratie"]);
            var training = EntityMapper.Map(_service.Retrieve("cref8_opleiding", duratieERef.Id, new ColumnSet("cref8_jaarstartopleiding")));

            var cursists = GetCursists("cref8_cursist", "cref8_opleiding_cref8_cursist", "cref8_cursistid", "cref8_opleidingid", training.Id);

            foreach (var cursist in cursists)
            {
                var traineeBudget = GetTraineeBudget(cursist, training);

                double nieuwAantalDagen = traineeBudget.RemainingDays   (duration.Hours / 8);
                Entity budget = new Entity("cref8_jaarlijkbudget");
                budget["cref8_jaarlijkbudgetid"] = traineeBudget.Id;
                budget["cref8_overigedagen"] = nieuwAantalDagen;

                _service.Update(budget);
            }
        }
        private static List GetCursists(string entityName, string linkToEntityName, string linkAttributeName, string attributeName, Guid id)
        {
            var query = new QueryExpression()
            {
                EntityName = entityName,
                ColumnSet = new ColumnSet("cref8_cursistid", "cref8_fullname")
            };
            var link = query.AddLink(linkToEntityName, linkAttributeName, linkAttributeName);
            link.LinkCriteria = new FilterExpression()
            {
                Conditions =
                                    {
                                        new ConditionExpression(attributeName, ConditionOperator.Equal, id)
                                    }
            };

            return _service.RetrieveMultiple(query).Entities.Select(e => EntityMapper.Map(e)).ToList();
        }
        private static TraineeBudget GetTraineeBudget(Cursist cursist, Training training)
        {
            ConditionExpression ceYearlyBudgetFromTrainee = new ConditionExpression("cref8_cursist", ConditionOperator.Equal, cursist.Id);
            ConditionExpression ceYearlyBudgetYear = new ConditionExpression("cref8_jaar", ConditionOperator.Equal, (int)training.Year);
            FilterExpression filter = new FilterExpression();
            filter.Conditions.Add(ceYearlyBudgetFromTrainee);
            filter.Conditions.Add(ceYearlyBudgetYear);
            QueryExpression qeYearlyBudget = new QueryExpression("cref8_jaarlijkbudget");
            qeYearlyBudget.ColumnSet = new ColumnSet("cref8_jaarlijkbudgetid", "cref8_overigedagen");
            qeYearlyBudget.Criteria.AddFilter(filter);
            EntityCollection yearlyBudgetResult = _service.RetrieveMultiple(qeYearlyBudget);

            return EntityMapper.Map(yearlyBudgetResult.Entities.First());
        }

    }
}

 

As you can see both Plugins do the same thing. They get the TraineeBudget of all Trainees and refund the ExtraKost or the Duration.

  • ExtraKost Plugin is firing but no calculations are done (I think Cursists are empty when Plugin code is executing)
  • Duration Plugin is firing and calculations are done correctly.

How can one Plugin work, and basically an identical Plugin does not work?

EDIT:

  • If I put the ExtraKost Delete plugin on Update message for ExtraKostname field for example and I trigger it the plugin works fine.
  • I Tried changing the Plugin to Prevalidation but also the plugin does not do any calculations

 

Best Regards,

Anthony

  • Verified answer
    Bipin D365 Profile Picture
    Bipin D365 28,964 Super User 2024 Season 1 on at
    RE: Two Identical Delete Plugins | One works, one doesn't

    Hi,

    For Delete operation -

    PreOperation- Record and related records will already be deleted from the system

    Prevalidation - Record and related records will still be present in the system

    Prevalidatation stage executes outside the database transaction, meaning when you create any record in Prevalidation plugin and something failed in preoperation plugin your records which you have created in prevalidation plugin will not be rolledback and still be present in the system

    That is why you were not getting any cursist record in your plugin when you registered on Pre-Operation stage.

    Please mark my answer verified if this is helpful!

    Regards,

    Bipin Kumar

    Follow my Blog: xrmdynamicscrm.wordpress.com/

  • AnthonyD Profile Picture
    AnthonyD 40 on at
    RE: Two Identical Delete Plugins | One works, one doesn't

    If I put Delete ExtraCost on PreValidation it works.. What is difference with PreOperation that not PreValidation it does work?

  • AnthonyD Profile Picture
    AnthonyD 40 on at
    RE: Two Identical Delete Plugins | One works, one doesn't

    Both are on Pre-operation

  • Mohsin Ali Profile Picture
    Mohsin Ali 3,610 on at
    RE: Two Identical Delete Plugins | One works, one doesn't

    Have you tried to to register steps for both the plugins to register at Pre-operation.

  • AnthonyD Profile Picture
    AnthonyD 40 on at
    RE: Two Identical Delete Plugins | One works, one doesn't

    UPDATE: I tried the same plugin on Message Update and everything is working fine for ExtraKost plugin. See pictures below. 

    Update message:

    You can see trace logs from inside the for each loop. 2 cursists were found.

    2022_2D00_01_2D00_13-15_5F00_43_5F00_37_2D00_Plug_2D00_in-Trace-Log_5F00_-TrainingBudget.Plugin.DeleteExtraCost_2C00_-TrainingBudget.Plugin_2C00_.png

    Delete message:

    You can see trace log "0".  which means no cursists were found in GetCursists() function.

    2022_2D00_01_2D00_13-15_5F00_43_5F00_55_2D00_Plug_2D00_in-Trace-Log_5F00_-TrainingBudget.Plugin.DeleteExtraCost_2C00_-TrainingBudget.Plugin_2C00_.png

    Same codes both on PreOperation with one working and one which doesn't.

    Any help would be appreciated

  • AnthonyD Profile Picture
    AnthonyD 40 on at
    RE: Two Identical Delete Plugins | One works, one doesn't

     Bipin Kumar 

    I added tracing in my code. You can see in the for each I also added tracing.

    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace TrainingBudget.Plugin
    {
    
        public class DeleteExtraCost : IPlugin
        {
            private static IOrganizationService _service;
            private IOrganizationServiceFactory _serviceFactory;
            private IPluginExecutionContext _context;
            private ITracingService _tracingService;
    
            public void Execute(IServiceProvider serviceProvider)
    
            {
                _context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
    
                if (_context.Depth > 1)
                {
                    return;
                }
    
                if (_context.MessageName != "Delete")
                {
                    return;
                }
                _serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
                _service = _serviceFactory.CreateOrganizationService(_context.UserId);
                _tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
    
                UpdateBudgets();
            }
            private void UpdateBudgets()
            {
                    _tracingService.Trace("Getting extra kosts.");
                    var extraKost = EntityMapper.Map(_context.PreEntityImages.FirstOrDefault(q => q.Key == "cref8_extrakost").Value);
                    EntityReference extraKostERef = ((EntityReference)_context.PreEntityImages.FirstOrDefault(q => q.Key == "cref8_extrakost").Value.Attributes["cref8_extrakosttraining"]);
                    _tracingService.Trace("Getting training.");
                    var training = EntityMapper.Map(_service.Retrieve("cref8_opleiding", extraKostERef.Id, new ColumnSet("cref8_jaarstartopleiding")));
                    _tracingService.Trace("Getting cursists.");
                    var cursists = GetCursists("cref8_cursist", "cref8_extrakost_cref8_cursist", "cref8_cursistid", "cref8_extrakostid", training.Id);
    
                    foreach (var cursist in cursists)
                    {
                    _tracingService.Trace("in for each loop for "   cursist.Id.ToString());
                        var traineeBudget = GetTraineeBudget(cursist, training);
    
                        double nieuwBudget = traineeBudget.RemainingBudget   extraKost.Price;
    
                        Entity budget = new Entity("cref8_jaarlijkbudget");
                        budget["cref8_jaarlijkbudgetid"] = traineeBudget.Id;
                        budget["cref8_overigebudget"] = nieuwBudget;
    
                        _service.Update(budget);
                    }
            }
            private static List GetCursists(string entityName, string linkToEntityName, string linkAttributeName, string attributeName, Guid id)
            {
                var query = new QueryExpression()
                {
                    EntityName = entityName,
                    ColumnSet = new ColumnSet("cref8_cursistid")
                };
                var link = query.AddLink(linkToEntityName, linkAttributeName, linkAttributeName);
                link.LinkCriteria = new FilterExpression()
                {
                    Conditions =
                                        {
                                            new ConditionExpression(attributeName, ConditionOperator.Equal, id)
                                        }
                };
    
                return _service.RetrieveMultiple(query).Entities.Select(e => EntityMapper.Map(e)).ToList();
            }
            private static TraineeBudget GetTraineeBudget(Cursist cursist, Training training)
            {
                ConditionExpression ceYearlyBudgetFromTrainee = new ConditionExpression("cref8_cursist", ConditionOperator.Equal, cursist.Id);
                ConditionExpression ceYearlyBudgetYear = new ConditionExpression("cref8_jaar", ConditionOperator.Equal, (int)training.Year);
                FilterExpression filter = new FilterExpression();
                filter.Conditions.Add(ceYearlyBudgetFromTrainee);
                filter.Conditions.Add(ceYearlyBudgetYear);
                QueryExpression qeYearlyBudget = new QueryExpression("cref8_jaarlijkbudget");
                qeYearlyBudget.ColumnSet = new ColumnSet("cref8_jaarlijkbudgetid", "cref8_overigebudget");
                qeYearlyBudget.Criteria.AddFilter(filter);
                EntityCollection yearlyBudgetResult = _service.RetrieveMultiple(qeYearlyBudget);
    
                return EntityMapper.Map(yearlyBudgetResult.Entities.First());
            }
    
        }
    }
    

    If I check trace log:

    2022_2D00_01_2D00_13-12_5F00_58_5F00_18_2D00_Plug_2D00_in-Trace-Log_5F00_-PluginProfiler.Plugins.ProfilerPlugin_2C00_-PluginProfiler.Plugins.png

    What disturbs me is the name from Plugin..

    My plugin assembly is called "TrainingBudget.Plugin"

    My plugin is called (Plugin) TrainingBudget.Plugin.DeleteExtraCost

    My step is called (Step) TrainingBudget.Plugin.DeleteExtraCost: Delete of cref8_extrakost (Profiled)

    Doesn't make any sense to me that typename is: PluginProfiler.Plugins.ProfilerPlugin, PluginProfiler.Plugins, Version=7.1.0.0, Culture=neutral, PublicKeyToken=***

    Do you see anything that could help me?

  • AnthonyD Profile Picture
    AnthonyD 40 on at
    RE: Two Identical Delete Plugins | One works, one doesn't

    I will look into adding tracing and checking audit history. Debugging the delete plugin won't work for me because on replaying the plugin, cursists are already empty so that for each is not firing.

  • Suggested answer
    Bipin D365 Profile Picture
    Bipin D365 28,964 Super User 2024 Season 1 on at
    RE: Two Identical Delete Plugins | One works, one doesn't

    Hi,

    I would recommend you to debug your plugin. Also add tracing in your code to check what value it is returning and till what point your plugin is getting executing.

    docs.microsoft.com/.../use-itracingservice-plugins

    Also, Check Audit history on your record. Do you have any other plugin which might be overiding the calculation.

    Debugging is your best approach to understand why calculation is not working.

    Please mark my answer verified if this is helpful!

    Regards,

    Bipin Kumar

    Follow my Blog: xrmdynamicscrm.wordpress.com/

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

December Spotlight Star - Muhammad Affan

Congratulations to a top community star!

Top 10 leaders for November!

Congratulations to our November super stars!

Community AMA December 12th

Join us as we continue to demystify the Dynamics 365 Contact Center

Leaderboard

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 291,240 Super User 2024 Season 2

#2
Martin Dráb Profile Picture

Martin Dráb 230,149 Most Valuable Professional

#3
nmaenpaa Profile Picture

nmaenpaa 101,156

Leaderboard

Featured topics

Product updates

Dynamics 365 release plans