Производительность плагина в Microsoft Dynamics CRM 2013/2015

Пора оставить застенчивый режим позади и сделать свой первый пост о stackoverflow. Проведя множество исследований (плагины, производительность, индексы, типы обновлений, друзья) и попробовав несколько подходов, я не смог найти правильный ответ / решение.

Так что, если возможно, я хотел бы получить ваш отзыв / помощь в решении проблемы производительности плагина Microsoft Dynamics CRM 2013/2015 (или техники кодирования).

Сценарий:

Microsoft Dynamics CRM 2013/2015
2 объекта со связью 1: N
EntityA
EntityB

EntityB имеет следующие столбцы:
Id | EntityAId | ColumnDemoX (десятичный) | ColumnDemoY (валюта)

У объекта A: 500 записей
У объекта B: 150 записей на каждую запись объекта A. Итак, 500 * 150 = 75000 записей.

Задача:

Создание объекта публикации. Обновление подключаемого модуля для «имитации» следующей команды SQL

Update EntityB
Set ColumnDemoX = (some quantity), ColumnDemoY = (some quantity) * (some value)
Where EntityAId = (some id)

Один из подходов мог бы быть таким:

using (var serviceContext = new XrmServiceContext(service)) 
{
  var query = from a in serviceContext.EntityASet
              where a.EntityAId.Equals(someId)
              select a;

  foreach (EntityA entA in query)
  {
    entA.ColumnDemoX = (some quantity);
    serviceContext.UpdateObject(entA);
  }

  serviceContext.SaveChanges();
}

Проблема:

Выполнение foreach для 150 записей в обновлении плагина публикации займет 20 секунд или более.
В то время как
Обновление EntityB устанавливает ColumnDemoX = (некоторое количество), ColumnDemoY = (некоторое количество) * (какое-то значение), где EntityAId = (некоторый идентификатор)
это займет 0,00001 с.

Любое предложение / решение?


Спасибо всем за то, что прочитали.
H


person Hugo L.    schedule 04.06.2015    source источник


Ответы (3)


Вы можете использовать ExecuteMultipleRequest, когда вы повторяете 150 объектов, сохраните сущности, которые нужно обновить, и после этого вызвать запрос. Если вы сделаете это, вы позвоните в службу только один раз, что очень хорошо для производительности.

Если ваш процесс может быть все больше и больше, вам следует подумать о том, чтобы сделать его асинхронным, как надстройку или рабочий процесс настраиваемого действия.

Это пример:

// Create an ExecuteMultipleRequest object.
requestWithResults = new ExecuteMultipleRequest()
{
    // Assign settings that define execution behavior: continue on error, return responses. 
    Settings = new ExecuteMultipleSettings()
    {
        ContinueOnError = false,
        ReturnResponses = true
    },
    // Create an empty organization request collection.
    Requests = new OrganizationRequestCollection()
};

// Add a UpdateRequest for each entity to the request collection.
foreach (var entity in input.Entities)
{
    UpdateRequest updateRequest = new UpdateRequest { Target = entity };
    requestWithResults.Requests.Add(updateRequest);
}

// Execute all the requests in the request collection using a single web method call.
ExecuteMultipleResponse responseWithResults =
    (ExecuteMultipleResponse)_serviceProxy.Execute(requestWithResults);
person Sxntk    schedule 04.06.2015
comment
не могли бы вы проверить эту тему ссылка Краткая Резюме: Таким образом, исходя из этих результатов, нет необходимости выполнять ExecuteMultipleRequest из подключаемого модуля. Вы уже находитесь на сервере, и вам нужно выполнить дополнительный код для выполнения той же операции. Спасибо за ответ Sxntk - person Hugo L.; 04.06.2015
comment
Примечание: извиняюсь за несколько правок в предыдущем комментарии, но я просто одновременно читаю справку по Markdown для stackoverflow :) - person Hugo L.; 04.06.2015
comment
Это довольно интересно, спасибо, что поделились, я считаю, что вы должны попробовать себя, Create and Update может изменить его поведение, попробуйте и сами посмотрите результаты. - person Sxntk; 04.06.2015
comment
Проведя несколько тестов, я могу подтвердить, что теория в этом ссылка верна. Использование executemultiplerequest внутри плагина нецелесообразно и фактически увеличивает время. - person Hugo L.; 05.06.2015
comment
Можно ли сделать этот процесс асинхронным? - person Sxntk; 05.06.2015
comment
ну, это не было желаемым решением, но в итоге я разделил код плагина. Теперь у меня есть плагин синхронизации и еще один для запуска асинхронной части. Спасибо за помощь @Sxntk - person Hugo L.; 17.06.2015

На ум приходит несколько решений, но я не думаю, что они вам понравятся ...

  1. Это действительно проблема? Да, это медленно, а обновление базы данных может быть намного быстрее. Однако, если вы можете использовать его как фоновый процесс (асинхронный), вы все равно будете иметь свои числа. Неужели это ситуация «Мне понадобятся эти числа в следующую секунду, как только я нажму кнопку, или бизнес пойдет не так»?

  2. Это может быть причиной отказаться от 2013 года. В CRM 2015 вы можете использовать вычисляемое поле. Если вам нужны эти числа только для отображения в формах (например, вы не используете их в отчетах), вы также можете сделать это в javascript.

  3. Предупреждение, это для отчаянного звонка. Если вам действительно нужно, чтобы обновление было синхронным, немедленным, вы не можете использовать вычисляемые поля, вы действительно знаете, что делаете и т. Д. Почему бы не сделать это прямо в базе данных? Я знаю, что это очень плохой совет. Есть много причин не делать это таким образом (вы можете прочитать несколько здесь). Он не поддерживается, и если вы сделаете что-то не так, все может пойти совсем плохо. Но если ваша реальная ситуация так же проста, как ваш пример (просто вычисляемое поле, без создания сущности, без изменения отношения), вы можете сделать это таким образом. Вам нужно будет учесть множество вещей: у вас не будет аудита полей, безопасности, проблем с кешированием, отсутствия изменений и т. Д. На самом деле я в значительной степени не рекомендую это решение.

person Nicolas C    schedule 08.06.2015
comment
1. Да, с точки зрения пользователя это проблема. Простое требование: измените что-то в форме, нажмите «Подтвердить / сохранить / выполнить», что должно обновить связанные записи, чтобы теперь пользователь мог обновить сетку, содержащую связанную информацию. У меня сейчас 2 плагина (один синхронный и другой асинхронный), но это лучшее из неидеальных решений, если вы понимаете, о чем я. ‹Br/› ‹hr /› 2. Расчетные поля в CRM. Вы не можете использовать значения в вычисляемых атрибутах, которые ссылаются на связанную сущность, поэтому я думаю, это не сработает. Помните, я пытаюсь обновить EntityB, когда обновляется Field1 на EntityA. - person Hugo L.; 17.06.2015
comment
3. Да, я знаю, что делаю, я знаю, что теряю, обходя CRM API, но я стараюсь найти поддерживаемый обходной путь, изменить логику бизнес-требований или объяснить заказчику ограничения программного обеспечения. ‹Br/› Николас большое спасибо за вашу помощь. Очень признателен. - person Hugo L.; 17.06.2015

1 - Поместите эту логику в асинхронный рабочий процесс. ИЛИ 2 - Не используйте
serviceContext.UpdateObject (entA);

serviceContext.SaveChanges () ;.

Получите все записи (150) после обновления полей и ExecuteMultipleRequest, чтобы обновить записи crm за один раз. Не отправлять запрос на обновление для каждой записи

person user1662380    schedule 17.06.2015
comment
Было принято решение разделить код, но на самом деле оно не реализует требуемую функцию. ‹Br/› Я попробовал пакетное обновление и ExecuteMultipleRequest, но проблема не исчезла. Прочтите мои комментарии к Sxntk и проверьте ссылку на другой поток Stackoverflow, где подробно описаны все тесты, включая тот, который вы предлагаете. Спасибо за вашу помощь - person Hugo L.; 17.06.2015