FetchXML与查询表达式与LINQ查询:在这里我应该使用什么?

时间:2018-07-16 19:03:13

标签: plugins dynamics-crm crm microsoft-dynamics xrm

我需要足够的帮助才能提供帮助!我正在运行Dynamics 365的实例,我需要确定是否使用FetchXML,LINQ查询或查询表达式来查询我称为合同行的实体的帮助。...

让我解释一下该项目:

在合同实体内部,我的合同行如下所示:

enter image description here

合同行(加总)将告诉您在整个合同期内每周的每一天订购什么(以及订购多少)。合同的期限可能超过6个月。.我要做的是获取此信息并将其扩展。所以我想获得从合同开始到合同结束的每一天的订单情况。创建合同后,将在另一个称为“单位订单”的实体中创建一条记录,如下所示:

enter image description here

在单元订单实体内部,存在另一个实体的子网格(称为alter unit order实体)。该实体与单元订单实体具有1:N的关系。就像来自合同实体的数据进入单元订单实体一样,我们希望来自合同行实体的数据进入变更单元订单实体。这里的技巧是编写一种算法,该算法处理合同行中的数据到更改单位订单实体中。我们总结了在合同的每一天为AM SNACK,午餐和PM SNACK订购了多少。请注意,订单仅在工作日完成(周末没有订单)。我已经开始编写插件,并且已经设法从合同实体中查询合同行子网格。我的问题是,我坚持这一点,我需要帮助来整理算法以吐出我想要的东西……这是我到目前为止所拥有的:

using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Query;


/// <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.PreOperation,
    ExecutionModeEnum.Synchronous,
    "title",
    "Post-Update Contract",
    1000,
    IsolationModeEnum.Sandbox,
    Image1Name = "PreImage",
    Image1Type = ImageTypeEnum.PreImage,
    Image1Attributes = "title")]
    public class UnitPlugin : IPlugin
    {



        public void Execute(IServiceProvider serviceProvider)
        {
            // Extract the tracing service for use in debugging sandboxed plug-ins.
            // Wil 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 colletion 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"];

                //verify that the target entity represents the the contract entity and is in an active state
                if (entity.LogicalName != "contract" && entity.GetAttributeValue<OptionSetValue>("statecode").Value != 0)
                    return;

                //obtain the organization service for web service calls.

                IOrganizationServiceFactory serviceFactory =
                        (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));

                IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            try
            {
                //Get Contract StartDate
                DateTime startDate = (DateTime)entity["activeon"];

                //Get Contract EndDate
                DateTime endDate = (DateTime)entity["expireson"];

                //Get all weekdays in the contract duration
                Eachday range = new Eachday();
                var weekdays = range.WeekDay(startDate, endDate);       //weekdays list

                //Get Contract Number
                string contractNumber = (string)entity["contractnumber"];


                //Query and aggregate each Weekday's order for the 3 different meal times...

                //AM SNACK


                //LUNCH


                //PM SNACK

                var am_list = new List<int>();
                var lunch_list = new List<int>();
                var pm_list = new List<int>();

                foreach(var day in weekdays)
                {
                    var alterunit = new Entity("new_alterunitorder");
                    alterunit.Attributes.Add("new_orderdate", DateTime.Parse(day));

                    switch (day.Split(',')[0])
                    {
                        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 ({day.Split(',')})");
                            break;

                    }
                    alterunit.Attributes.Add("new_name", contractNumber);
                    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;

                }
            }
        }
    }
}

这是我用来在合同期限内获取所有工作日的代码:

public class Eachday
{
    public List<string> WeekDay(DateTime from, DateTime thru)
    {
        List<string> days_list = new List<string>();
        for (var day = from.Date; day.Date <= thru.Date; day = day.AddDays(1))
        {
            days_list.Add(day.ToLongDateString());
            if (day.DayOfWeek == DayOfWeek.Sunday || day.DayOfWeek == DayOfWeek.Saturday)
                days_list.Remove(day.ToShortDateString());
        }

        return days_list;
    }

我在try块中添加了此代码,以获取工作日列表:

                //Get Contract StartDate
                DateTime startDate = (DateTime)entity["activeon"];

                //Get Contract EndDate
                DateTime endDate = (DateTime)entity["expireson"];

                //Get all weekdays in the contract duration
                Eachday range = new Eachday();
                var weekdays = range.WeekDay(startDate, endDate);

我需要将每周的每周订购数量放入清单中。本质上,我将有3个列表。然后我将使用列表中的开关吐出总数!

                foreach(var day in weekdays)
                {
                    var alterunit = new Entity("new_alterunitorder");
                    alterunit.Attributes.Add("new_orderdate", DateTime.Parse(day));

                    switch (day.Split(',')[0])
                    {
                        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 ({day.Split(',')})");
                            break;

                    }
                    alterunit.Attributes.Add("new_name", contractNumber);
                    service.Create(alterunit);
                }

1 个答案:

答案 0 :(得分:1)

我看到您是首次使用插件。我发现QueryExpression通常非常复杂。相反,您应该使用fetchXml。简而言之,fetchXml是Dynamics中查询的语言。所有视图都使用它。您可以在高级查找窗口中生成fetchXml。

enter image description here

就性能而言,它也是最好的。据我所知,在插件中没有其他选择可以计算总和而不检索内存中的全部数据。

这是我在MSDN中找到的一个例子

string estimatedvalue_sum = @"  <fetch distinct='false' mapping='logical' aggregate='true'> 
    <entity name='opportunity'> 
       <attribute name='estimatedvalue' alias='estimatedvalue_sum' aggregate='sum' /> 
    </entity>  </fetch>";

EntityCollection estimatedvalue_sum_result =
_serviceProxy.RetrieveMultiple(new FetchExpression(estimatedvalue_sum));

foreach (var c in estimatedvalue_sum_result.Entities) {
    decimal aggregate7 = ((Money)((AliasedValue)c["estimatedvalue_sum"]).Value).Value;
    System.Console.WriteLine("Sum of estimated value of all opportunities: " + aggregate7);

}

来源:https://msdn.microsoft.com/en-us/library/gg309565.aspx#sum

此外,这是一些一般性提示:

  • _serviceProxy是服务变量
  • 在目标中,您会发现发生了什么变化
  • 在上图中,您会发现更改之前的情况
  • 当您在同一事件上触发不同的插件时,张贴图片非常有用,我始终建议避免这种情况。将所有内容都放在同一个类中,可以为您提供更多的控制权。

第一次修订: 您可以创建一个包含每天总金额的实体。用正确的类型替换“(金钱)”。不确定是货币还是整数。

foreach(var unit in unitsum_am_result.Entities)
{
    decimal mondaySum = ((Money)((AliasedValue)unit["new_mondayunits_amsum"]).Value).Value;
    decimal tuesdaySum = ((Money)((AliasedValue)unit["new_tuesdayunits_amsum"]).Value).Value;
    decimal wednesdaySum = ((Money)((AliasedValue)unit["new_unitswednesday_amsum"]).Value).Value;
    decimal thursdaySum = ((Money)  ((AliasedValue)unit["new_unitsthursday_amsum"]).Value).Value;
    decimal fridaySum = ((Money)        ((AliasedValue)unit["new_unitsfriday_amsum"]).Value).Value;

    var unitOrder = new Entity("new_unit_order");
    unitOrder.Attributes.Add("new_orderSum", mondaySum);
    unitOrder.Attributes.Add("new_date", mondayDate);
    _serviceProxy.Create(unitOrder);

    // Do the same for the other sums/days
}

第二次修订 为了从合同中获得查找值,最好的选择是使用插件注册工具在插件上创建原像。在图像中,选择您需要从实体中检索的字段。它像目标一样工作。

PluginExecutionContext.PreEntityImages != null && PluginExecutionContext.PreEntityImages.Count >= 1 ? PluginExecutionContext.PreEntityImages.FirstOrDefault().Value : null;

enter image description here

请注意,如果在更新事件中未修改单位,则将在图像中找到该值。如果确实要更新单位,则会在图像中找到旧值,而在目标中找到新值。因此,您始终必须同时检查两者。