恰好创建了 33 条记录后插件执行停止,原因是什么?
Plugin Execution Halts After exactly 33 records created, What is the cause?
我有一个插件可以在名为 "Alter Unit Order" 的实体中创建记录。它应该为从合同开始日期到合同结束日期的每一天创建记录。无论如何,该插件只会创建 33 条记录。我认为这可能是因为进行了多少 FetchXML 查询。如果是这样,修复方法是什么?
这里是插件的代码:
using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Plugins;
/// <summary>
/// This plugin takes the data provided in the contract lines and makes Unit Orders..
/// Inside the unit orders, an Alter Unit Orders table is present.
/// The Alter Unit Orders table describes the daily order for each day in the contract's duration.
/// </summary>
namespace DCWIMS.Plugins
{
[CrmPluginRegistration(MessageNameEnum.Update,
"contract",
StageEnum.PostOperation,
ExecutionModeEnum.Asynchronous,
"statecode",
"Post-Update Contract",
1000,
IsolationModeEnum.Sandbox,
Image1Name = "PreImage",
Image1Type = ImageTypeEnum.PreImage,
Image1Attributes = "")]
public class UnitPlugin : 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));
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
//obtain the target entity from the input parameters.
Entity entity = (Entity)context.InputParameters["Target"];
//Get the before image of the updated contract
Entity PreImage = context.PreEntityImages["PreImage"];
//verify that the target entity represents the the contract entity and contract is Active (statecode 2)
if (entity.LogicalName != "contract" || entity.GetAttributeValue<OptionSetValue>("statecode").Value != 2)
return;
//Redundancy to prevent execution when going from Hold/cancel to active
if (PreImage.GetAttributeValue<OptionSetValue>("statecode").Value == 3 || entity.Contains("cancelon"))
return;
//obtain the organization service for web service calls.
IOrganizationServiceFactory serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
//This will be used as service for web service calls
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//Core Plugin Code in try block
try
{
//Get Contract StartDate
DateTime startDate = (DateTime)PreImage["activeon"];
//Get Contract EndDate
DateTime endDate = (DateTime)PreImage["expireson"];
//Create an instance of the range class
Eachday range = new Eachday();
//use Weekday method of range class to get a weekdays list
var weekdays = range.WeekDay(startDate, endDate);
//Get Contract Number
string contractNumber = (string)PreImage["contractnumber"];
//Get Unit Order Lookup Id
EntityReference unitOrder = (EntityReference)PreImage.Attributes["new_unitorderid"];
var unitOrderId = unitOrder.Id;
//Query for the different Location Destinations and Serving Groups
string fetch = @" <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='true'>
<entity name='contractdetail'>
<attribute name='new_servinggroup' alias='serving' />
<attribute name='new_locationdestination' />
<filter type='and'>
<condition attribute='new_locationdestination' operator='not-null' />
</filter>
<link-entity name='contract' from='contractid' to='contractid' alias='ad'>
<filter type='and'>
<condition attribute='contractnumber' operator='eq' value='" + contractNumber + @"' />
</filter>
</link-entity>
</entity>
</fetch>";
//Put fetch result into an entity collection
EntityCollection result =
service.RetrieveMultiple(new FetchExpression(fetch));
//iterate through entire contract duration and create the records
foreach (var day in weekdays)
{
var currentday = day.Split(',')[0];
//Create a record for each Serving Group and Destination pair
foreach (var ent in result.Entities)
{
//Get the Serving Group
AliasedValue aliasedValue = ent.GetAttributeValue<AliasedValue>("serving");
object aliasValue = aliasedValue.Value;
OptionSetValue optionset = (OptionSetValue)aliasValue;
int group = optionset.Value;
//Get the location destination
var location = ent.GetAttributeValue<string>("new_locationdestination");
//Create the record and fill the attributes
Entity alterunit = new Entity("new_alterunitorder");
alterunit.Attributes.Add("new_orderdate", DateTime.Parse(day));
alterunit.Attributes.Add("new_name", contractNumber);
alterunit.Attributes["new_orderlineid"] =
new EntityReference("new_units", unitOrderId);
var selection = new OptionSetValue(group);
alterunit.Attributes["new_servinggroup"] = selection;
alterunit.Attributes.Add("new_location", location);
//use Fetch Query here and feed the switch below
//Fetch AM SUM for the current serving group and location
string fetch_am = @" <fetch aggregate = 'true' distinct = 'false' >
<entity name = 'contractdetail' >
<attribute name = 'new_mondayunits' alias = 'new_mondayunits_sum' aggregate = 'sum' />
<attribute name = 'new_tuesdayunits' alias = 'new_tuesdayunits_sum' aggregate = 'sum' />
<attribute name = 'new_unitswednesday' alias = 'new_unitswednesday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsthursday' alias = 'new_unitsthursday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsfriday' alias = 'new_unitsfriday_sum' aggregate = 'sum' />
<filter type='and' >
<condition value= '100000001' attribute = 'new_servingtime' operator = 'eq' />
<condition value = '" + group + @"' attribute = 'new_servinggroup' operator= 'eq' />
<condition value = '" + location + @"' attribute = 'new_locationdestination' operator= 'eq' />
<condition value = '0' attribute = 'statecode' operator= 'eq' />
</filter >
<link-entity name = 'contract' from = 'contractid' to = 'contractid' alias = 'aa'>
<filter type = 'and' >
<condition attribute = 'contractnumber' operator= 'eq' value = '" + contractNumber + @"' />
</filter >
</link-entity >
</entity >
</fetch > ";
var fetch_one = new FetchQuery(fetch_am);
var am_list = fetch_one.Result(serviceProvider);
//Fetch LUNCH SUM for the current serving group and location
string fetch_lunch = @" <fetch aggregate = 'true' distinct = 'false' >
<entity name = 'contractdetail' >
<attribute name = 'new_mondayunits' alias = 'new_mondayunits_sum' aggregate = 'sum' />
<attribute name = 'new_tuesdayunits' alias = 'new_tuesdayunits_sum' aggregate = 'sum' />
<attribute name = 'new_unitswednesday' alias = 'new_unitswednesday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsthursday' alias = 'new_unitsthursday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsfriday' alias = 'new_unitsfriday_sum' aggregate = 'sum' />
<filter type='and' >
<condition value= '100000002' attribute = 'new_servingtime' operator = 'eq' />
<condition value = '" + group + @"' attribute = 'new_servinggroup' operator= 'eq' />
<condition value = '" + location + @"' attribute = 'new_locationdestination' operator= 'eq' />
<condition value = '0' attribute = 'statecode' operator= 'eq' />
</filter >
<link-entity name = 'contract' from = 'contractid' to = 'contractid' alias = 'aa'>
<filter type = 'and' >
<condition attribute = 'contractnumber' operator= 'eq' value = '" + contractNumber + @"' />
</filter >
</link-entity >
</entity >
</fetch >";
var fetch_two = new FetchQuery(fetch_lunch);
var lunch_list = fetch_two.Result(serviceProvider);
//Fetch PM SUM for the current Serving Group and location
string fetch_pm = @" <fetch aggregate = 'true' distinct = 'false' >
<entity name = 'contractdetail' >
<attribute name = 'new_mondayunits' alias = 'new_mondayunits_sum' aggregate = 'sum' />
<attribute name = 'new_tuesdayunits' alias = 'new_tuesdayunits_sum' aggregate = 'sum' />
<attribute name = 'new_unitswednesday' alias = 'new_unitswednesday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsthursday' alias = 'new_unitsthursday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsfriday' alias = 'new_unitsfriday_sum' aggregate = 'sum' />
<filter type='and' >
<condition value= '100000003' attribute = 'new_servingtime' operator = 'eq' />
<condition value = '" + group + @"' attribute = 'new_servinggroup' operator= 'eq' />
<condition value = '" + location + @"' attribute = 'new_locationdestination' operator= 'eq' />
<condition value = '0' attribute = 'statecode' operator= 'eq' />
</filter >
<link-entity name = 'contract' from = 'contractid' to = 'contractid' alias = 'aa'>
<filter type = 'and' >
<condition attribute = 'contractnumber' operator= 'eq' value = '" + contractNumber + @"' />
</filter >
</link-entity >
</entity >
</fetch >";
var fetch_three = new FetchQuery(fetch_pm);
var pm_list = fetch_three.Result(serviceProvider);
switch (currentday)
{
case "Monday":
alterunit.Attributes.Add("new_amsnack", am_list[0]);
alterunit.Attributes.Add("new_lunch", lunch_list[0]);
alterunit.Attributes.Add("new_pmsnack", pm_list[0]);
break;
case "Tuesday":
alterunit.Attributes.Add("new_amsnack", am_list[1]);
alterunit.Attributes.Add("new_lunch", lunch_list[1]);
alterunit.Attributes.Add("new_pmsnack", pm_list[1]);
break;
case "Wednesday":
alterunit.Attributes.Add("new_amsnack", am_list[2]);
alterunit.Attributes.Add("new_lunch", lunch_list[2]);
alterunit.Attributes.Add("new_pmsnack", pm_list[2]);
break;
case "Thursday":
alterunit.Attributes.Add("new_amsnack", am_list[3]);
alterunit.Attributes.Add("new_lunch", lunch_list[3]);
alterunit.Attributes.Add("new_pmsnack", pm_list[3]);
break;
case "Friday":
alterunit.Attributes.Add("new_amsnack", am_list[4]);
alterunit.Attributes.Add("new_lunch", lunch_list[4]);
alterunit.Attributes.Add("new_pmsnack", pm_list[4]);
break;
default:
Console.WriteLine($"An unexpected value ({currentday})");
break;
}
service.Create(alterunit);
}
}
}
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;
}
}
}
}
}
是的,我明白了。 foreach 循环是 运行 每次迭代查询 3 次。每次迭代都会创建一条记录。 33 次迭代的 3 次查询是 99 次查询。加上 foreach 循环之前的 1 个 fetchxml 查询,总共有 100 个查询。 Microsoft 对每条消息有 100 个查询的服务器端限制。这就是为什么我每次只创建 33 条记录。
我有一个插件可以在名为 "Alter Unit Order" 的实体中创建记录。它应该为从合同开始日期到合同结束日期的每一天创建记录。无论如何,该插件只会创建 33 条记录。我认为这可能是因为进行了多少 FetchXML 查询。如果是这样,修复方法是什么?
这里是插件的代码:
using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using Plugins;
/// <summary>
/// This plugin takes the data provided in the contract lines and makes Unit Orders..
/// Inside the unit orders, an Alter Unit Orders table is present.
/// The Alter Unit Orders table describes the daily order for each day in the contract's duration.
/// </summary>
namespace DCWIMS.Plugins
{
[CrmPluginRegistration(MessageNameEnum.Update,
"contract",
StageEnum.PostOperation,
ExecutionModeEnum.Asynchronous,
"statecode",
"Post-Update Contract",
1000,
IsolationModeEnum.Sandbox,
Image1Name = "PreImage",
Image1Type = ImageTypeEnum.PreImage,
Image1Attributes = "")]
public class UnitPlugin : 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));
// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
//obtain the target entity from the input parameters.
Entity entity = (Entity)context.InputParameters["Target"];
//Get the before image of the updated contract
Entity PreImage = context.PreEntityImages["PreImage"];
//verify that the target entity represents the the contract entity and contract is Active (statecode 2)
if (entity.LogicalName != "contract" || entity.GetAttributeValue<OptionSetValue>("statecode").Value != 2)
return;
//Redundancy to prevent execution when going from Hold/cancel to active
if (PreImage.GetAttributeValue<OptionSetValue>("statecode").Value == 3 || entity.Contains("cancelon"))
return;
//obtain the organization service for web service calls.
IOrganizationServiceFactory serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
//This will be used as service for web service calls
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);
//Core Plugin Code in try block
try
{
//Get Contract StartDate
DateTime startDate = (DateTime)PreImage["activeon"];
//Get Contract EndDate
DateTime endDate = (DateTime)PreImage["expireson"];
//Create an instance of the range class
Eachday range = new Eachday();
//use Weekday method of range class to get a weekdays list
var weekdays = range.WeekDay(startDate, endDate);
//Get Contract Number
string contractNumber = (string)PreImage["contractnumber"];
//Get Unit Order Lookup Id
EntityReference unitOrder = (EntityReference)PreImage.Attributes["new_unitorderid"];
var unitOrderId = unitOrder.Id;
//Query for the different Location Destinations and Serving Groups
string fetch = @" <fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='true'>
<entity name='contractdetail'>
<attribute name='new_servinggroup' alias='serving' />
<attribute name='new_locationdestination' />
<filter type='and'>
<condition attribute='new_locationdestination' operator='not-null' />
</filter>
<link-entity name='contract' from='contractid' to='contractid' alias='ad'>
<filter type='and'>
<condition attribute='contractnumber' operator='eq' value='" + contractNumber + @"' />
</filter>
</link-entity>
</entity>
</fetch>";
//Put fetch result into an entity collection
EntityCollection result =
service.RetrieveMultiple(new FetchExpression(fetch));
//iterate through entire contract duration and create the records
foreach (var day in weekdays)
{
var currentday = day.Split(',')[0];
//Create a record for each Serving Group and Destination pair
foreach (var ent in result.Entities)
{
//Get the Serving Group
AliasedValue aliasedValue = ent.GetAttributeValue<AliasedValue>("serving");
object aliasValue = aliasedValue.Value;
OptionSetValue optionset = (OptionSetValue)aliasValue;
int group = optionset.Value;
//Get the location destination
var location = ent.GetAttributeValue<string>("new_locationdestination");
//Create the record and fill the attributes
Entity alterunit = new Entity("new_alterunitorder");
alterunit.Attributes.Add("new_orderdate", DateTime.Parse(day));
alterunit.Attributes.Add("new_name", contractNumber);
alterunit.Attributes["new_orderlineid"] =
new EntityReference("new_units", unitOrderId);
var selection = new OptionSetValue(group);
alterunit.Attributes["new_servinggroup"] = selection;
alterunit.Attributes.Add("new_location", location);
//use Fetch Query here and feed the switch below
//Fetch AM SUM for the current serving group and location
string fetch_am = @" <fetch aggregate = 'true' distinct = 'false' >
<entity name = 'contractdetail' >
<attribute name = 'new_mondayunits' alias = 'new_mondayunits_sum' aggregate = 'sum' />
<attribute name = 'new_tuesdayunits' alias = 'new_tuesdayunits_sum' aggregate = 'sum' />
<attribute name = 'new_unitswednesday' alias = 'new_unitswednesday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsthursday' alias = 'new_unitsthursday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsfriday' alias = 'new_unitsfriday_sum' aggregate = 'sum' />
<filter type='and' >
<condition value= '100000001' attribute = 'new_servingtime' operator = 'eq' />
<condition value = '" + group + @"' attribute = 'new_servinggroup' operator= 'eq' />
<condition value = '" + location + @"' attribute = 'new_locationdestination' operator= 'eq' />
<condition value = '0' attribute = 'statecode' operator= 'eq' />
</filter >
<link-entity name = 'contract' from = 'contractid' to = 'contractid' alias = 'aa'>
<filter type = 'and' >
<condition attribute = 'contractnumber' operator= 'eq' value = '" + contractNumber + @"' />
</filter >
</link-entity >
</entity >
</fetch > ";
var fetch_one = new FetchQuery(fetch_am);
var am_list = fetch_one.Result(serviceProvider);
//Fetch LUNCH SUM for the current serving group and location
string fetch_lunch = @" <fetch aggregate = 'true' distinct = 'false' >
<entity name = 'contractdetail' >
<attribute name = 'new_mondayunits' alias = 'new_mondayunits_sum' aggregate = 'sum' />
<attribute name = 'new_tuesdayunits' alias = 'new_tuesdayunits_sum' aggregate = 'sum' />
<attribute name = 'new_unitswednesday' alias = 'new_unitswednesday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsthursday' alias = 'new_unitsthursday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsfriday' alias = 'new_unitsfriday_sum' aggregate = 'sum' />
<filter type='and' >
<condition value= '100000002' attribute = 'new_servingtime' operator = 'eq' />
<condition value = '" + group + @"' attribute = 'new_servinggroup' operator= 'eq' />
<condition value = '" + location + @"' attribute = 'new_locationdestination' operator= 'eq' />
<condition value = '0' attribute = 'statecode' operator= 'eq' />
</filter >
<link-entity name = 'contract' from = 'contractid' to = 'contractid' alias = 'aa'>
<filter type = 'and' >
<condition attribute = 'contractnumber' operator= 'eq' value = '" + contractNumber + @"' />
</filter >
</link-entity >
</entity >
</fetch >";
var fetch_two = new FetchQuery(fetch_lunch);
var lunch_list = fetch_two.Result(serviceProvider);
//Fetch PM SUM for the current Serving Group and location
string fetch_pm = @" <fetch aggregate = 'true' distinct = 'false' >
<entity name = 'contractdetail' >
<attribute name = 'new_mondayunits' alias = 'new_mondayunits_sum' aggregate = 'sum' />
<attribute name = 'new_tuesdayunits' alias = 'new_tuesdayunits_sum' aggregate = 'sum' />
<attribute name = 'new_unitswednesday' alias = 'new_unitswednesday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsthursday' alias = 'new_unitsthursday_sum' aggregate = 'sum' />
<attribute name = 'new_unitsfriday' alias = 'new_unitsfriday_sum' aggregate = 'sum' />
<filter type='and' >
<condition value= '100000003' attribute = 'new_servingtime' operator = 'eq' />
<condition value = '" + group + @"' attribute = 'new_servinggroup' operator= 'eq' />
<condition value = '" + location + @"' attribute = 'new_locationdestination' operator= 'eq' />
<condition value = '0' attribute = 'statecode' operator= 'eq' />
</filter >
<link-entity name = 'contract' from = 'contractid' to = 'contractid' alias = 'aa'>
<filter type = 'and' >
<condition attribute = 'contractnumber' operator= 'eq' value = '" + contractNumber + @"' />
</filter >
</link-entity >
</entity >
</fetch >";
var fetch_three = new FetchQuery(fetch_pm);
var pm_list = fetch_three.Result(serviceProvider);
switch (currentday)
{
case "Monday":
alterunit.Attributes.Add("new_amsnack", am_list[0]);
alterunit.Attributes.Add("new_lunch", lunch_list[0]);
alterunit.Attributes.Add("new_pmsnack", pm_list[0]);
break;
case "Tuesday":
alterunit.Attributes.Add("new_amsnack", am_list[1]);
alterunit.Attributes.Add("new_lunch", lunch_list[1]);
alterunit.Attributes.Add("new_pmsnack", pm_list[1]);
break;
case "Wednesday":
alterunit.Attributes.Add("new_amsnack", am_list[2]);
alterunit.Attributes.Add("new_lunch", lunch_list[2]);
alterunit.Attributes.Add("new_pmsnack", pm_list[2]);
break;
case "Thursday":
alterunit.Attributes.Add("new_amsnack", am_list[3]);
alterunit.Attributes.Add("new_lunch", lunch_list[3]);
alterunit.Attributes.Add("new_pmsnack", pm_list[3]);
break;
case "Friday":
alterunit.Attributes.Add("new_amsnack", am_list[4]);
alterunit.Attributes.Add("new_lunch", lunch_list[4]);
alterunit.Attributes.Add("new_pmsnack", pm_list[4]);
break;
default:
Console.WriteLine($"An unexpected value ({currentday})");
break;
}
service.Create(alterunit);
}
}
}
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;
}
}
}
}
}
是的,我明白了。 foreach 循环是 运行 每次迭代查询 3 次。每次迭代都会创建一条记录。 33 次迭代的 3 次查询是 99 次查询。加上 foreach 循环之前的 1 个 fetchxml 查询,总共有 100 个查询。 Microsoft 对每条消息有 100 个查询的服务器端限制。这就是为什么我每次只创建 33 条记录。