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

FetchXML vs Query Expression vs LINQ Query: What should I use here?

我需要好心人的帮助!我是 运行 Dynamics 365 的一个实例,我需要帮助来决定是使用 FetchXML、LINQ 查询还是查询表达式来查询我称为合同行的实体....

让我解释一下这个项目:

在合同实体中,我有如下所示的合同行:

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

在单元订单实体内部,有另一个实体(称为更改单元订单实体)的子网格。该实体与单位订单实体具有 1:N 关系。就像合同实体中的数据进入单位订单实体一样,我们希望合同行实体中的数据进入变更单位订单实体。这里的技巧是编写一种算法,将合同行中的数据处理到更改单元订单实体中。我们正在计算合同中每一天上午小吃、午餐和下午小吃的订购量。请注意,订单仅在工作日完成(周末没有订单)。我已经开始编写插件,并且已经设法从合同实体查询合同行子网格。我的问题是,我一直坚持这一点,我需要帮助将算法组合在一起以吐出我想要的东西......这是我目前所拥有的:

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 个列表。然后我会使用 switch 中的列表来计算总数!!

                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);
                }

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

在性能方面,也是最好的。据我所知,在插件中没有其他选项可以在不检索内存中的全部数据的情况下计算总和。

这是我在 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是服务变量
  • 在目标中,您会发现发生了什么变化
  • 在预映像中,您将找到更改之前的内容
  • Post 当您在同一事件上触发不同的插件时,图像很有用,我总是建议避免这种情况。保持一切相同 class,它给了你更多的控制权。

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

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
}

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

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

请注意,如果您在更新事件中不修改单位,您会在图像中找到该值。如果您确实更新了单位,您将在图像中找到旧值,在目标中找到新值。所以你总是必须检查两者。