Здравствуйте!
сегодня писал тригер на афтер апдейт, который создает запись, если изменилось значение в поле Пример на Завершено в другой записи. Так вот, тригер создает две идентичные записи подряд.
Не успел подебагить: либо тригер в целом срабатывает дважды, либо главный цикл тригера по каким то причинам делает два оборота (новая запись не вставляется в главном цикле, в нем собирается лист новых записей, и вне цикла они вставляется за один инсерт). Нужно еще проверить, что именно происходит.
К слову на изменение значения в поле Пример на Завершено должен срабатывать Ворк Флоу и менять другое поле в данной записи. Неужели он провоцирует повторную сработку тригера? но в условия тригера есть ("Завершено" !=Trigger.oldMap.get(Объект.Id).Пример__c), те он не должен срабатывать после какого-либо обновления (спровоцированного ВоркФлоу) если в поле Пример уже было значение "Завершено" . Кроме того и сам тригер на афтер апдейт, те тот ВоркФлоу который я подозреваю должен сработать до тригера.... Буду разбираться.
Здравствуйте! сегодня писал тригер на афтер апдейт, который создает запись, если изменилось значение в поле Пример на Завершено в другой записи. Так вот, тригер создает две идентичные записи подряд. Не успел подебагить: либо тригер в целом срабатывает дважды, либо главный цикл тригера по каким то причинам делает два оборота (новая запись не вставляется в главном цикле, в нем собирается лист новых записей, и вне цикла они вставляется за один инсерт). Нужно еще проверить, что именно происходит. К слову на изменение значения в поле Пример на Завершено должен срабатывать Ворк Флоу и менять другое поле в данной записи. Неужели он провоцирует повторную сработку тригера? но в условия тригера есть ("Завершено" !=Trigger.oldMap.get(Объект.Id).Пример__c), те он не должен срабатывать после какого-либо обновления (спровоцированного ВоркФлоу) если в поле Пример уже было значение "Завершено" . Кроме того и сам тригер на афтер апдейт, те тот ВоркФлоу который я подозреваю должен сработать до тригера.... Буду разбираться.
Большая вероятность того, что у тебя триггер срабатывает дважды.
Это легко проверить - поставь в самом начала триггера SYSTEM.DEBUG('some trigger fired');
и посмотри в debug log. Сколько записей найдешь, столько раз у тебя сработал триггер.
На счет одновременной работы воркфлов и триггера это уже тяжелый случай. Лучше так не делать. Либо одно, либо другое. Иначе будут проблемы.
А так тебе в помощь только debug log поможет. Учись его читать
В общем на счет многократного срабатывания триггера - есть такой тип проблемы. Раньше пару раз сталкивался. Если это не связано с кривым кодом, а просто по логике так получается, то есть кастыль на этот случай. Надо сделать статический класс со статической переменной и выставлять в ней какое-нибудь значение при входе в триггер. И опять же в триггере проверять это значений. Если значение в статической переменной найдено, то это говорит о том, что триггер уже сработал и повторный его запуск можно отменять.
Большая вероятность того, что у тебя триггер срабатывает дважды. Это легко проверить - поставь в самом начала триггера SYSTEM.DEBUG('some trigger fired'); и посмотри в debug log. Сколько записей найдешь, столько раз у тебя сработал триггер. На счет одновременной работы воркфлов и триггера это уже тяжелый случай. Лучше так не делать. Либо одно, либо другое. Иначе будут проблемы. А так тебе в помощь только debug log поможет. Учись его читать :) В общем на счет многократного срабатывания триггера - есть такой тип проблемы. Раньше пару раз сталкивался. Если это не связано с кривым кодом, а просто по логике так получается, то есть кастыль на этот случай. Надо сделать статический класс со статической переменной и выставлять в ней какое-нибудь значение при входе в триггер. И опять же в триггере проверять это значений. Если значение в статической переменной найдено, то это говорит о том, что триггер уже сработал и повторный его запуск можно отменять.
Все так и было Дмитрий.
Вот только на прошлых выходных я прочел об этом в книге Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста.
И вот оно.
Нужен класс со статик переменной.
Статик переменный объявленные внутри тригера не живут весь ран контектс.
Все так и было Дмитрий. Вот только на прошлых выходных я прочел об этом в книге Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста. И вот оно. Нужен класс со статик переменной. Статик переменный объявленные внутри тригера не живут весь ран контектс.
Так точно я для этого использую ENV класс, который всегда знает что сейчас выполняется
[quote="Den Brown"]Все так и было Дмитрий. Вот только на прошлых выходных я прочел об этом в книге Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста. И вот оно. Нужен класс со статик переменной. Статик переменный объявленные внутри тригера не живут весь ран контектс.[/quote] Так точно я для этого использую ENV класс, который всегда знает что сейчас выполняется
[quote="Den Brown"]Все так и было Дмитрий. Вот только на прошлых выходных я прочел об этом в книге Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста. И вот оно. Нужен класс со статик переменной. Статик переменный объявленные внутри тригера не живут весь ран контектс.[/quote] Буду очень признателен если поделишься книгой.Заранее спасибо. :)
А как это работает?
я создал:
public class StaticHelper {
public static integer helper;
}
и вначале тригера - проверка значение в helper
и в конце тригера
StaticHelper.helper=1;
и для каждого тригера нужно создавать свой вспомогательный класс или добавлять в существующий новое статичное поле
[quote="wilder"] Так точно я для этого использую ENV класс, который всегда знает что сейчас выполняется[/quote] А как это работает? я создал: [code]public class StaticHelper { public static integer helper; }[/code] и вначале тригера - проверка значение в helper и в конце тригера [code]StaticHelper.helper=1;[/code] и для каждого тригера нужно создавать свой вспомогательный класс или добавлять в существующий новое статичное поле
книга физическая, не электронная.
могу на работе читать, но не могу никаким образом копировать - права, права...
по мере прочтения - могу делится светлыми мыслями, почерпнутыми из нее, на форуме.
Вот и сама книжка на амазоне:
[url]http://www.amazon.com/Advanced-Apex-Programming-Salesforce-com-Force-com/dp/1936754053" rel="nofollow" target="_blank">http://www.amazon.com/Advanced-Apex-Programming-Salesforce-com-Force-com/dp/1936754053" rel="nofollow" target="_blank">
[url]http://www.amazon.com/Advanced-Apex-Programming-Salesforce-com-Force-com/dp/1936754053
[quote="Sergey Prichepo"] Буду очень признателен если поделишься книгой.Заранее спасибо. :)[/quote] книга физическая, не электронная. могу на работе читать, но не могу никаким образом копировать - права, права... по мере прочтения - могу делится светлыми мыслями, почерпнутыми из нее, на форуме. Вот и сама книжка на амазоне: [url] [url]http://www.amazon.com/Advanced-Apex-Programming-Salesforce-com-Force-com/dp/1936754053[/url][/url]
Вот мой вариант.
Пример использования :
trigger TRGR_Contact on Contact (before insert, before update) {
Integer Cnt = Env.setTriggersRun(true,null);
if (Trigger.isBefore && Trigger.isInsert) {
HNDL_Contact.setHistory(trigger.New, null);
}
if (Trigger.isBefore && Trigger.isUpdate) {
HNDL_Contact.setHistory(trigger.New, trigger.oldMap);
}
Env.setTriggersRun(false, Cnt);
}
Сам класс в приложении. [Расширение cls запрещено администратором.] это еще почему ?
Log example :
[0][START] OpportunityLineItem [BEFORE : UPDATE](1)
[0][END] OpportunityLineItem [BEFORE : UPDATE] SOQL Count : [0] (1)
[0][START] OpportunityLineItem [AFTER : UPDATE](1)
[1][START] Forecast_Line__c [BEFORE : UPDATE](3)
[1][END] Forecast_Line__c [BEFORE : UPDATE] SOQL Count : [3] (3)
[1][START] Yearly_Quota__c [BEFORE : UPDATE](1)
[1][END] Yearly_Quota__c [BEFORE : UPDATE] SOQL Count : [4] (1)
[1][START] Yearly_Quota__c [AFTER : UPDATE](1)
[1][END] Yearly_Quota__c [AFTER : UPDATE] SOQL Count : [5] (1)
[0][END] OpportunityLineItem [AFTER : UPDATE] SOQL Count : [1] (1)
[0][START] OpportunityLineItem [BEFORE : UPDATE](1)
[0][END] OpportunityLineItem [BEFORE : UPDATE] SOQL Count : [1] (1)
[0][START] OpportunityLineItem [AFTER : UPDATE](1)
[1][START] Forecast_Line__c [BEFORE : UPDATE](3)
[1][END] Forecast_Line__c [BEFORE : UPDATE] SOQL Count : [8] (3)
[0][END] OpportunityLineItem [AFTER : UPDATE] SOQL Count : [2] (1)
[0][START] Opportunity [BEFORE : UPDATE](1)
[0][END] Opportunity [BEFORE : UPDATE] SOQL Count : [2] (1)
[0][START] Opportunity [AFTER : UPDATE](1)
[0][END] Opportunity [AFTER : UPDATE] SOQL Count : [3] (1)
Count RUNS : 10
[quote="Sergey Prichepo"][quote="Den Brown"]Все так и было Дмитрий. Вот только на прошлых выходных я прочел об этом в книге Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста. И вот оно. Нужен класс со статик переменной. Статик переменный объявленные внутри тригера не живут весь ран контектс.[/quote] Буду очень признателен если поделишься книгой.Заранее спасибо. :)[/quote] Вот мой вариант. Пример использования : trigger TRGR_Contact on Contact (before insert, before update) { Integer Cnt = Env.setTriggersRun(true,null); if (Trigger.isBefore && Trigger.isInsert) { HNDL_Contact.setHistory(trigger.New, null); } if (Trigger.isBefore && Trigger.isUpdate) { HNDL_Contact.setHistory(trigger.New, trigger.oldMap); } Env.setTriggersRun(false, Cnt); } Сам класс в приложении. [Расширение cls запрещено администратором.] это еще почему ? Log example : [0][START] OpportunityLineItem [BEFORE : UPDATE](1) [0][END] OpportunityLineItem [BEFORE : UPDATE] SOQL Count : [0] (1) [0][START] OpportunityLineItem [AFTER : UPDATE](1) [1][START] Forecast_Line__c [BEFORE : UPDATE](3) [1][END] Forecast_Line__c [BEFORE : UPDATE] SOQL Count : [3] (3) [1][START] Yearly_Quota__c [BEFORE : UPDATE](1) [1][END] Yearly_Quota__c [BEFORE : UPDATE] SOQL Count : [4] (1) [1][START] Yearly_Quota__c [AFTER : UPDATE](1) [1][END] Yearly_Quota__c [AFTER : UPDATE] SOQL Count : [5] (1) [0][END] OpportunityLineItem [AFTER : UPDATE] SOQL Count : [1] (1) [0][START] OpportunityLineItem [BEFORE : UPDATE](1) [0][END] OpportunityLineItem [BEFORE : UPDATE] SOQL Count : [1] (1) [0][START] OpportunityLineItem [AFTER : UPDATE](1) [1][START] Forecast_Line__c [BEFORE : UPDATE](3) [1][END] Forecast_Line__c [BEFORE : UPDATE] SOQL Count : [8] (3) [0][END] OpportunityLineItem [AFTER : UPDATE] SOQL Count : [2] (1) [0][START] Opportunity [BEFORE : UPDATE](1) [0][END] Opportunity [BEFORE : UPDATE] SOQL Count : [2] (1) [0][START] Opportunity [AFTER : UPDATE](1) [0][END] Opportunity [AFTER : UPDATE] SOQL Count : [3] (1) Count RUNS : 10
Сам класс в приложении. [Расширение cls запрещено администратором.] это еще почему ?
Пока не знаю, по видимому дефолтные настройки форума. Исправлю.
[quote]Сам класс в приложении. [Расширение cls запрещено администратором.] это еще почему ?[/quote] Пока не знаю, по видимому дефолтные настройки форума. Исправлю.
Появилась неожиданная проблема.
Со слов коллег, они не могут установить деплой сет с тригером и классом со статичной переменной в другой орг. Выдается ошибка, что такой (статичной) переменной не существует (хотя они клянутся, что отгрузили этот вспомогательный класс в сет).
КРоме того уже вижу, что они покрыли тестом тригер который использует эту стат переменную на 100%, а покрытие этого класса со статичной переменной в исходящем орге при это 0%. Как это может быть.
Но главная проблема именно с переносом - толи они что-то не так делают, то ли с переносом кода использующего стат переменные действительно какие-то проблемы....
PS а нет - сделали они деплой, при чем не могут объяснить, что они сделали :)
Появилась неожиданная проблема. Со слов коллег, они не могут установить деплой сет с тригером и классом со статичной переменной в другой орг. Выдается ошибка, что такой (статичной) переменной не существует (хотя они клянутся, что отгрузили этот вспомогательный класс в сет). КРоме того уже вижу, что они покрыли тестом тригер который использует эту стат переменную на 100%, а покрытие этого класса со статичной переменной в исходящем орге при это 0%. Как это может быть. Но главная проблема именно с переносом - толи они что-то не так делают, то ли с переносом кода использующего стат переменные действительно какие-то проблемы.... PS а нет - сделали они деплой, при чем не могут объяснить, что они сделали :)
мне кажется что кто-то что-то не договаривает (намекаю на "тех")
Никаких проблем со статической переменной не должно и не может быть. По всей вероятности не включили в changeSet класс.
:) мне кажется что кто-то что-то не договаривает (намекаю на "тех") Никаких проблем со статической переменной не должно и не может быть. По всей вероятности не включили в changeSet класс.
:) мне кажется что кто-то что-то не договаривает (намекаю на "тех")Никаких проблем со статической переменной не должно и не может быть. По всей вероятности не включили в changeSet класс.
Или тесты валятся на Exception каком-либо.
[quote="Dmitry Shnyrev"]:) мне кажется что кто-то что-то не договаривает (намекаю на "тех") Никаких проблем со статической переменной не должно и не может быть. По всей вероятности не включили в changeSet класс.[/quote] Или тесты валятся на Exception каком-либо.
Все отгрузили они. Но не признаются, что сделали.
Ну ладно - нет проблем со стат переменными при переносе - и здорово.
Но вот почему тригер покрыт на 100%, а класс с одной единственной переменной, которую он использует - покрыт на 0% - я не знаю.
Все отгрузили они. Но не признаются, что сделали. Ну ладно - нет проблем со стат переменными при переносе - и здорово. Но вот почему тригер покрыт на 100%, а класс с одной единственной переменной, которую он использует - покрыт на 0% - я не знаю.