问题
The overall question is: How do I access entity variables that are not in my collection (haven't been updated) in a plugin for D365 CRM?
I have been wrestling with this for quite a while, and now, I turn to you, the forum Gods, for help in understanding what's happening here.
I have customizations on the Work Order entity within D365 CRM (v9.0). Essentially, whenever one of three fields is updated, I need to perform the same logic each time. For whatever reason, the plugin will ONLY work when all three fields are updated in a single operation. If I just update one, I will get the "key not present in dictionary" error, signifying that my variable is not in the current collection.
I have tried to alter my "contains" check to be contains XYZ || contains ABC || contains 123, but that fails instantly. Then, I tried to nest each of those conditions within each other, but of course, the lowest nests don't get touched. Then I tried to un-nest, and just try each of the "contains" checks individually, and go ahead and do the logic in all three if blocks. All of this has failed me to this point.
Is there something I am missing here? For testing purposes, I have it set to fire on All Attributes (not just the three that i want to check on), but even that fails for me. I also spoke with a colleague who has quite a bit more experience than I do in the development side of the house for CRM, and you can see some of the artifacts there in the "FieldValue" function calls (though I have stripped out the FieldValue function from this code snip).
I am new-ish to CRM development, but have been working in MSCRM since 4.0.
Any advice is greatly appreciated.
The overall question is: How do I access entity variables that are not in my collection (haven't been updated) in a plugin for D365 CRM?
Code below, with references to my client's names removed:
using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;
using Microsoft.Crm.Sdk.Messages;
using System.ServiceModel;
using System.Data.SqlClient;
using System.Threading.Tasks;
namespace ClientNTE
{
public class NTEExceedance : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
IOrganizationServiceFactory factory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = factory.CreateOrganizationService(context.UserId);
//Extract the tracing service for use in debugging sandboxed plug-ins.
ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
Money subtotal = null;
Money nte = null;
Decimal nte_percent = 0;
Decimal subtotalDecimal = 0;
Decimal nteDecimal = 0;
Decimal amountDiffDecimal = 0;
Decimal percentDifference = 0;
try
{
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
{
Entity entity = (Entity)context.InputParameters["Target"];
if (entity.LogicalName == "msdyn_workorder")
{
//code fires onChange of NTE Amount (same logic will apply to NTE % and Est Subtotal Amount)
if (entity.Attributes.Contains("CLIENT_nteamount") == true)
{
//trying to use the FieldValue function to grab these fields into collection, commented out for now
//String NewValue = FieldValue(service, new Guid(entity["msdyn_workorderid"].ToString()));
//String NewSubTotal = FieldValue(service, new Guid(entity["msdyn_workorderid"].ToString()), entity["msdyn_estimatesubtotalamount"].ToString());
//String NewNTE = FieldValue(service, new Guid(entity["msdyn_workorderid"].ToString()), entity["CLIENT_nteamount"].ToString());
//String Newpercent = FieldValue(service, new Guid(entity["msdyn_workorderid"].ToString()), entity["CLIENT_ntepercent"].ToString());
subtotal = (Money)entity.Attributes["msdyn_estimatesubtotalamount"];
nte = (Money)entity.Attributes["CLIENT_nteamount"];
nte_percent = (Decimal)entity.Attributes["CLIENT_ntepercent"];
subtotalDecimal = subtotal.Value;
nteDecimal = nte.Value;
amountDiffDecimal = (subtotalDecimal - nteDecimal);
percentDifference = ((amountDiffDecimal / nteDecimal) * 100);
// decimal percentDifference = 100;
//decimal nte_percent = 50;
if (percentDifference > nte_percent)
{
//know this snippet works
entity["CLIENT_nteexceeded"] = true;
}
if (percentDifference <= nte_percent)
{
//know this snippet works
entity["CLIENT_nteexceeded"] = false;
}
}
if (entity.Attributes.Contains("CLIENT_ntepercent") == true)
{
subtotal = (Money)entity.Attributes["msdyn_estimatesubtotalamount"];
nte = (Money)entity.Attributes["CLIENT_nteamount"];
nte_percent = (Decimal)entity.Attributes["CLIENT_ntepercent"];
subtotalDecimal = subtotal.Value;
nteDecimal = nte.Value;
amountDiffDecimal = (subtotalDecimal - nteDecimal);
percentDifference = ((amountDiffDecimal / nteDecimal) * 100);
// decimal percentDifference = 100;
//decimal nte_percent = 50;
if (percentDifference > nte_percent)
{
//know this snippet works
entity["CLIENT_nteexceeded"] = true;
}
if (percentDifference <= nte_percent)
{
//know this snippet works
entity["CLIENT_nteexceeded"] = false;
}
}
if (entity.Attributes.Contains("msdyn_estimatesubtotalamount") == true)
{
subtotal = (Money)entity.Attributes["msdyn_estimatesubtotalamount"];
nte = (Money)entity.Attributes["CLIENT_nteamount"];
nte_percent = (Decimal)entity.Attributes["CLIENT_ntepercent"];
subtotalDecimal = subtotal.Value;
nteDecimal = nte.Value;
amountDiffDecimal = (subtotalDecimal - nteDecimal);
percentDifference = ((amountDiffDecimal / nteDecimal) * 100);
// decimal percentDifference = 100;
//decimal nte_percent = 50;
if (percentDifference > nte_percent)
{
//know this snippet works
entity["CLIENT_nteexceeded"] = true;
}
if (percentDifference <= nte_percent)
{
//know this snippet works
entity["CLIENT_nteexceeded"] = false;
}
/*
Money m = (Money)entity.Attributes["new_evalmoneyvalue"];
decimal actualAmount = m.Value;
entity["new_evaldecimal"] = actualAmount;
entity["new_evalmoneyvalue"] = new Money((decimal)actualAmount * 2);
*/
}
}
}
}
catch (FaultException<OrganizationServiceFault> e)
{
tracingService.Trace("CLIENTPlugin - Update NTEExceededNonCalc: {0}", e.ToString());
throw e;
}
}
}
}
回答1:
How do I access entity variables that are not in my collection (haven't been updated) in a plugin for D365 CRM?
Answer: Images (Pre-Image or Post-Image)
Register an Image with necessary attributes in Update step, so you will get the whole entity object or every single attribute you mark. Basically its an efficient Retrieve call by platform & serve you in Context itself.
For example in your case, register the Post-Update step with PreImage (all 3 attributes). So the modified attribute will be in (Entity)context.InputParameters["Target"]
. Unmodified attributes can be consumed from (Entity)context.PreEntityImages["Image"]
. Read more
Also Contains may come as true always, so check the Money/Decimal fields like explained here.
Money myMoneyField = (Money)EntityObject.GetAttributeValue<Money>(Amount);
decimal actualAmount;
if (myMoneyField != null)
{
actualAmount = myMoneyField.Value;
}
Now you have the attribute values before & after the transaction, hence you decide & store the value to use in calculation.
Entity orderEntity = (Entity)context.InputParameters["Target"];
Entity preOrderEntity = (Entity)context.PreEntityImages["Image"];
Decimal preNTEamount = preOrderEntity.GetAttributeValue<Money>("CLIENT_nteamount") != null ? ((Money)preOrderEntity.GetAttributeValue<Money>("CLIENT_nteamount")).Value : 0;
Decimal newNTEamount = orderEntity.GetAttributeValue<Money>("CLIENT_nteamount") != null ? ((Money)orderEntity.GetAttributeValue<Money>("CLIENT_nteamount")).Value : preNTEamount;
来源:https://stackoverflow.com/questions/50915478/dynamics-365-crm-online-use-a-field-that-is-not-in-collection-hasnt-been-upd