WedX - журнал о программировании и компьютерных науках

Dynamics 365 CRM Online - Используйте поле, которого НЕТ в коллекции (не обновлено)

Общий вопрос: как мне получить доступ к переменным сущности, которых нет в моей коллекции (не обновлялись) в подключаемом модуле для D365 CRM?

Я долго боролся с этим, и теперь я обращаюсь к вам, боги форума, за помощью в понимании того, что здесь происходит.

У меня есть настройки объекта "Заказ на работу" в D365 CRM (v9.0). По сути, всякий раз, когда обновляется одно из трех полей, мне нужно каждый раз выполнять одну и ту же логику. По какой-то причине плагин будет работать ТОЛЬКО при обновлении всех трех полей за одну операцию. Если я просто обновлю один, я получу ошибку «ключ отсутствует в словаре», означающий, что моей переменной нет в текущей коллекции.

Я попытался изменить мою проверку "содержит", чтобы она содержала XYZ || содержит ABC || содержит 123, но это сразу же не удается. Затем я попытался вложить каждое из этих условий друг в друга, но, конечно же, самые нижние гнезда не затрагиваются. Затем я попытался разложить и просто попробовать каждую из проверок «содержит» по отдельности, а затем выполнить логику во всех трех блоках if. Все это до сих пор меня не подводило.

Что-то мне здесь не хватает? В целях тестирования я настроил его на запуск по всем атрибутам (а не только по трем, которые я хочу проверить), но даже это для меня не работает. Я также поговорил с коллегой, у которого гораздо больше опыта, чем у меня, в области разработки CRM, и вы можете увидеть некоторые артефакты в вызовах функции "FieldValue" (хотя я исключил FieldValue функция из этого фрагмента кода).

Я новичок в разработке CRM, но работаю в MSCRM с 4.0.
Любые советы приветствуются.

Общий вопрос: как мне получить доступ к переменным объекта, которых нет в моей коллекции (не обновлялись) в плагине для D365 CRM?

Код ниже, в котором удалены ссылки на имена моих клиентов:

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

    }

}

  • Логика невероятно проста - и срабатывает, как и ожидалось, если я включаю все 3 переменные в свою операцию обновления (через пользовательский интерфейс). Меня сбивает с толку, что так сложно заставить логику срабатывать независимо от того, находятся ли данные в «коллекции» или нет - они есть в сущности, и я беру ее из записи сущности! Я также планирую сделать все три этих поля обязательными. Это должен был быть плагин, позволяющий выполнять операцию без открытия форм (правила Biz и JScript не подойдут для этого требования). 18.06.2018

Ответы:


1

Как мне получить доступ к переменным сущности, которых нет в моей коллекции (не обновлялись) в плагине для D365 CRM?

Ответ: Изображения (предварительное изображение или пост-изображение)

Зарегистрируйте изображение с необходимыми атрибутами на этапе обновления, чтобы получить весь объект сущности или каждый отдельный атрибут, который вы отметили. По сути, это эффективный вызов Retrieve на платформе и обслуживание в самом контексте.

Например, в вашем случае зарегистрируйте шаг Post-Update с PreImage (все 3 атрибута). Таким образом, измененный атрибут будет в (Entity)context.InputParameters["Target"]. Неизмененные атрибуты можно использовать из (Entity)context.PreEntityImages["Image"]. Узнать больше

Также Contains может всегда выполняться, поэтому проверьте поля Money / Decimal, как описано здесь.

Money myMoneyField = (Money)EntityObject.GetAttributeValue<Money>(Amount);

decimal actualAmount;

if (myMoneyField != null)
{
    actualAmount = myMoneyField.Value;
}

Теперь у вас есть значения атрибутов до и после транзакции, поэтому вы решаете и сохраняете значение для использования в расчетах.

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;
18.06.2018
  • Арун - Спасибо за быстрый ответ! Я перешел на предварительную версию своего кода, и, похоже, она работает должным образом. Спасибо! В качестве продолжения (которого меня могут сторониться, и мне придется разместить здесь новую ветку ...) - Мой плагин запускается только КАЖДЫЙ ДРУГОЙ раз, когда я его запускаю. То есть я вызываю его, изменяя одно из трех полей, и оно не обновляет целевое поле в записи. Когда я снова запускаю его, изменяя значение того же поля, плагин запускается, и получаются ожидаемые результаты. Есть мысли относительно того, почему это могло произойти? Еще раз спасибо, чувак! 18.06.2018
  • @BrianFrick Нет проблем. Я предполагаю, что плагин будет запускаться каждый раз, но не обновляет поле в том смысле, что там может быть некоторая логическая ошибка. Попробуйте отладить код с помощью профилировщика. 18.06.2018
  • Спасибо чувак. Я пару раз отлаживал / профилировал, и у меня ничего не выскочило (все переменные выглядели хорошо, выглядело так, будто ДОЛЖЕН установить мой да / нет, но нет), но человек, я потратил так много времени, пытаясь сделать это БЕЗ предварительного -image, я думаю, что пора закончить день и забрать резервную копию рано утром с новой сессией отладки. Еще раз спасибо за то, что нашли время написать свои мысли - очень полезно! 18.06.2018
  • Новые материалы

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..


    Для любых предложений по сайту: [email protected]