Hi experts,
I have a issue on my delete plugins. I have 2 delete plugins. Both are identical.
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.
How can one Plugin work, and basically an identical Plugin does not work?
EDIT:
Best Regards,
Anthony
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/
If I put Delete ExtraCost on PreValidation it works.. What is difference with PreOperation that not PreValidation it does work?
Both are on Pre-operation
Have you tried to to register steps for both the plugins to register at Pre-operation.
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.
Delete message:
You can see trace log "0". which means no cursists were found in GetCursists() function.
Same codes both on PreOperation with one working and one which doesn't.
Any help would be appreciated
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:
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?
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.
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/
Stay up to date on forum activity by subscribing. You can also customize your in-app and email Notification settings across all subscriptions.
André Arnaud de Cal... 291,240 Super User 2024 Season 2
Martin Dráb 230,149 Most Valuable Professional
nmaenpaa 101,156