I have a parent entity and child entity. I'm creating a plugin to count number of child entities for each parent entity and display the number in noOfProduct
field in parent entity. So every time when I created a new child entity, the value of number in noOfProduct
will be increment to 1. But when I deleted the child entity, my plugin is not triggering, hence the value remain the same.
I registered my plugin,
step: create
primary entity: child_entity
event_pipeline: post-operation
synchronous
Plugin Images: post-image
This is my complete code.
using System;
using System.IO;
using System.ServiceModel;
using System.ServiceModel.Description;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Xrm.Sdk.Messages;
using Microsoft.Xrm.Sdk.Client;
using System.Net;
using System.Web.Services;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace NoOfProductsPlugin
{
public class NoOfProducts : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//for create and update event
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parmameters.
Entity targetEntity = (Entity)context.InputParameters["Target"];
// Verify that the entity represents a connection.
if (targetEntity.LogicalName != "child_entity")
{
return;
}
else
{
try
{
//triggered upon create or update message
if (context.MessageName == "Create" || context.MessageName == "Update")
{
Entity postMessageImage;
Guid oppId = new Guid();
if (context.PostEntityImages.Contains("postMessageImage") && context.PostEntityImages["postMessageImage"] is Entity)
{
postMessageImage = (Entity)context.PostEntityImages["postMessageImage"];
oppId = ((EntityReference)postMessageImage.Attributes["lookup_fieldtoParent"]).Id;
}
//throw new InvalidPluginExecutionException
queryOppProd(service, oppId);
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred :-" + ex.Message, ex);
}
//</snippetFollowupPlugin3>
catch (Exception ex)
{
tracingService.Trace("An error occurred : {0}" + ex.Message, ex.ToString());
throw;
}
}
}
//for delete event use entityreference
else if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is EntityReference)
{
// Obtain the target entity from the input parmameters.
EntityReference targetEntity = (EntityReference)context.InputParameters["Target"];
// Verify that the entity represents a connection.
if (targetEntity.LogicalName != "child_entity")
{
return;
}
else
{
try
{
//triggered upon delete message
if (context.MessageName == "Delete")
{
Guid oppProdId = targetEntity.Id;
// retrieve oppid guid
Entity oppProd = new Entity("child_entity");
ColumnSet columns_ = new ColumnSet(new string[] { "lookup_fieldtoParent" });
oppProd = service.Retrieve(oppProd.LogicalName, oppProdId, columns_);
Guid oppId = new Guid();
oppId = ((EntityReference)oppProd["lookup_fieldtoParent"]).Id;
//throw new InvalidPluginExecutionException(
}
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred :-" + ex.Message, ex);
}
//</snippetFollowupPlugin3>
catch (Exception ex)
{
tracingService.Trace("An error occurred: {0}" + ex.Message, ex.ToString());
throw;
}
}
}
}
public void queryOppProd(IOrganizationService service, Guid oppId)
{
int noOfProduct = 0;
QueryExpression oppProdQuery = new QueryExpression { EntityName = "child_entity", ColumnSet = new ColumnSet("child_entityid", "lookup_fieldtoParent") };
oppProdQuery.Criteria.AddCondition("lookup_fieldtoParent", ConditionOperator.Equal, oppId); // to search for child_entity that linked to the selected parent_entity
EntityCollection oppProdQueryRetrieve = service.RetrieveMultiple(oppProdQuery);
if (oppProdQueryRetrieve != null && oppProdQueryRetrieve.Entities.Count > 0)
{
for (var i = 0; i < oppProdQueryRetrieve.Entities.Count; i++)
{
noOfProduct++;
}
}
//declare table used to retrieve the field and update
Entity opportunity = new Entity("parent_entity");
ColumnSet columns = new ColumnSet(new string[] { "new_noofproducts" });
opportunity = service.Retrieve(opportunity.LogicalName, oppId, columns);
opportunity["new_noofproducts"] = noOfProduct;
service.Update(opportunity);
}
public void queryOppProdOnDel(IOrganizationService service, Guid oppId, Guid oppProdId)
{
int noOfProduct = 0;
//query opportunityProduct by using opportunity guid
QueryExpression oppProdQuery = new QueryExpression { EntityName = "child_entity", ColumnSet = new ColumnSet("child_entityid", "lookup_fieldtoParent") };
FilterExpression oppProdQueryFilter = oppProdQuery.Criteria.AddFilter(LogicalOperator.And);
oppProdQueryFilter.AddCondition("child_entityid", ConditionOperator.NotEqual, oppProdId);
oppProdQueryFilter.AddCondition("lookup_fieldtoParent", ConditionOperator.Equal, oppId); // to search for child_entity that linked to the selected parent_entity
EntityCollection oppProdQueryRetrieve = service.RetrieveMultiple(oppProdQuery);
if (oppProdQueryRetrieve != null && oppProdQueryRetrieve.Entities.Count > 0)
{
for (var i = 0; i < oppProdQueryRetrieve.Entities.Count; i++)
{
noOfProduct++;
}
}
//throw new InvalidPluginExecutionException
//declare table used to retrieve the field and update
Entity opportunity = new Entity("parent_entity");
ColumnSet columns = new ColumnSet(new string[] { "new_noofproducts" });
opportunity = service.Retrieve(opportunity.LogicalName, oppId, columns);
service.Update(opportunity);
}
}
}
Couple of points:
step: create
You should register on delete
. Pretty sure post-image is not supported on delete. You need to use pre's. "The create operation doesn't support a pre-image and a delete operation doesn't support a post-image."
Your basic design has a flaw. If lots of changes occur at the same time, they could all execute concurrently on seperate threads, this means the count could be incorrect in some circumstances.
You forgot to call the method queryOppProdOnDel
.
When you register your Plugin assembly & Step on Delete message, replace the below snippet in your code.
//triggered upon delete message
if (context.MessageName == "Delete")
{
Guid oppProdId = targetEntity.Id;
// retrieve oppid guid
Entity oppProd = new Entity("child_entity");
ColumnSet columns_ = new ColumnSet(new string[] { "lookup_fieldtoParent" });
oppProd = service.Retrieve(oppProd.LogicalName, oppProdId, columns_);
Guid oppId = new Guid();
oppId = ((EntityReference)oppProd["lookup_fieldtoParent"]).Id;
//throw new InvalidPluginExecutionException(
queryOppProdOnDel(service, oppId, oppProdId);
}
Update:
This line is missing in queryOppProdOnDel
:
opportunity["new_noofproducts"] = noOfProduct;
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.