Регистрация  |  Вход

Тригер срабатывает дважды

Здравствуйте!
сегодня писал тригер на афтер апдейт, который создает запись, если изменилось значение в поле Пример на Завершено в другой записи. Так вот, тригер создает две идентичные записи подряд.

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

К слову на изменение значения в поле Пример на Завершено должен срабатывать Ворк Флоу и менять другое поле в данной записи. Неужели он провоцирует повторную сработку тригера? но в условия тригера есть ("Завершено" !=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 может привести к повторной сработке тригера в пределах одного ран контекста.

И вот оно.

Нужен класс со статик переменной.

Статик переменный объявленные внутри тригера не живут весь ран контектс.

Den Brown
Все так и было Дмитрий.

Вот только на прошлых выходных я прочел об этом в книге Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста.

И вот оно.

Нужен класс со статик переменной.

Статик переменный объявленные внутри тригера не живут весь ран контектс.

Так точно я для этого использую ENV класс, который всегда знает что сейчас выполняется

[quote="Den Brown"]Все так и было Дмитрий.

Вот только на прошлых выходных я прочел об этом в книге  Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста.

И вот оно.

Нужен класс со статик переменной.

Статик переменный объявленные внутри тригера не живут весь ран контектс.[/quote]

Так точно я для этого использую ENV класс, который всегда знает что сейчас выполняется

Den Brown
Все так и было Дмитрий.

Вот только на прошлых выходных я прочел об этом в книге Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста.

И вот оно.

Нужен класс со статик переменной.

Статик переменный объявленные внутри тригера не живут весь ран контектс.


Буду очень признателен если поделишься книгой.Заранее спасибо. :)

[quote="Den Brown"]Все так и было Дмитрий.

Вот только на прошлых выходных я прочел об этом в книге  Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста.

И вот оно.

Нужен класс со статик переменной.

Статик переменный объявленные внутри тригера не живут весь ран контектс.[/quote]
Буду очень признателен если поделишься книгой.Заранее спасибо.  :)

wilder
Так точно я для этого использую ENV класс, который всегда знает что сейчас выполняется

А как это работает?

я создал:

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]

и для каждого тригера нужно создавать свой вспомогательный класс или добавлять в существующий новое статичное поле

Sergey Prichepo
Буду очень признателен если поделишься книгой.Заранее спасибо. :)

книга физическая, не электронная.

могу на работе читать, но не могу никаким образом копировать - права, права...

по мере прочтения - могу делится светлыми мыслями, почерпнутыми из нее, на форуме.

Вот и сама книжка на амазоне:

[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]

Sergey Prichepo
Den Brown
Все так и было Дмитрий.

Вот только на прошлых выходных я прочел об этом в книге Дена Аплмена, о том что специфика разработки в SFDC в том, что разработчик знает когда ран контекст начинается, но никогда не знает когда данный конкретный ран контектс закончится - так на него влияют WFR - которые настраивают админы системы, не разработчики - а дествия этих WFR может привести к повторной сработке тригера в пределах одного ран контекста.

И вот оно.

Нужен класс со статик переменной.

Статик переменный объявленные внутри тригера не живут весь ран контектс.


Буду очень признателен если поделишься книгой.Заранее спасибо. :)

Вот мой вариант.

Пример использования :

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 класс.

Dmitry Shnyrev
:) мне кажется что кто-то что-то не договаривает (намекаю на "тех")

Никаких проблем со статической переменной не должно и не может быть. По всей вероятности не включили в changeSet класс.

Или тесты валятся на Exception каком-либо.

[quote="Dmitry Shnyrev"]:) мне кажется что кто-то что-то не договаривает (намекаю на "тех")

Никаких проблем со статической переменной не должно и не может быть. По всей вероятности не включили в changeSet класс.[/quote]

Или тесты валятся на Exception каком-либо.

Все отгрузили они. Но не признаются, что сделали.

Ну ладно - нет проблем со стат переменными при переносе - и здорово.
Но вот почему тригер покрыт на 100%, а класс с одной единственной переменной, которую он использует - покрыт на 0% - я не знаю.

Все отгрузили они. Но не признаются, что сделали. 

Ну ладно - нет проблем со стат переменными при переносе - и здорово. 
Но вот почему тригер покрыт на 100%, а класс с одной единственной переменной, которую он использует - покрыт на 0% - я не знаю.