trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
HttpRequest req = new HttpRequest();
req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=006P0000004NPIA4');
req.setMethod('POST');Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
}
При отработке тригера выдается ошибка
Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger OpportunityRemoteUpdate caused an unexpected exception, contact your administrator: OpportunityRemoteUpdate: execution of AfterUpdate caused by: System.CalloutException: Callout from triggers are currently not supported.: Trigger.OpportunityRemoteUpdate: line 7, column 1
В чем может быть проблема?
[code]trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) { HttpRequest req = new HttpRequest(); req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=006P0000004NPIA4'); req.setMethod('POST'); Http http = new Http(); HTTPResponse res = http.send(req); System.debug(res.getBody()); }[/code] При отработке тригера выдается ошибка Error: Invalid Data. Review all error messages below to correct your data. Apex trigger OpportunityRemoteUpdate caused an unexpected exception, contact your administrator: OpportunityRemoteUpdate: execution of AfterUpdate caused by: System.CalloutException: Callout from triggers are currently not supported.: Trigger.OpportunityRemoteUpdate: line 7, column 1 В чем может быть проблема?
Вот тут есть ответ на ваш вопрос.
Дело в том что в Salesforce есть такой нюанс - нельзя делать callout после DML операции. А триггер запускается в результате DML операции. Тут необходимо использовать @future метод. Но учтите, что это асинхронная операция и в debug log будет отображаться как отдельный процесс после основного.
Процетирую
You do need to use the @future annotation in an apex method that is stored in a separate class. Then call that class and method from within your trigger.
For example:
trigger justAnExample on Account (after update){
testCls.myMethod(); //call the static method, with the @future annotation
}
global testCls {
@future Public static void myMethod(callout=true){
System.debug('inside myMethod...');
//do your callout logic here...
System.debug('exiting myMethod...');
}
}
Вот тут есть ответ на ваш вопрос. [url]http://boards.developerforce.com/t5/Apex-Code-Development/Callout-from-triggers-are-currently-not-supported/td-p/108871[/url] Дело в том что в Salesforce есть такой нюанс - нельзя делать callout после DML операции. А триггер запускается в результате DML операции. Тут необходимо использовать @future метод. Но учтите, что это асинхронная операция и в debug log будет отображаться как отдельный процесс после основного. Процетирую You do need to use the @future annotation in an apex method that is stored in a separate class. Then call that class and method from within your trigger. For example: trigger justAnExample on Account (after update){ testCls.myMethod(); //call the static method, with the @future annotation } global testCls { @future Public static void myMethod(callout=true){ System.debug('inside myMethod...'); //do your callout logic here... System.debug('exiting myMethod...'); } }
Да действительно так работает!
Есть еще одна проблема - когда я хочу передать параметр trigger.newMap
trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
Opportunity_TriggerHelper.updateOpportunity(trigger.newMap);
}
public with sharing class Opportunity_TriggerHelper {
@future (callout=true)
public static void updateOpportunity (Map<Id, Opportunity> newMap);
HttpRequest req = new HttpRequest();
req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx');
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
}
}
то при сохранении класса получаю ошибку: Error: Compile Error: expecting a right parentheses, found 'http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx' at line 5 column 21
причем если передавать string в качестве параметра то все норм, например так:
trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
String OpportunityId = 'xxxxx';
Opportunity_TriggerHelper.updateOpportunity(OpportunityId);
}
public with sharing class Opportunity_TriggerHelper {
@future (callout=true)
public static void updateOpportunity (String OpportunityId) {
HttpRequest req = new HttpRequest();
req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id='+OpportunityId);
req.setMethod('GET');
Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
}
}
Да действительно так работает! Есть еще одна проблема - когда я хочу передать параметр trigger.newMap trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) { Opportunity_TriggerHelper.updateOpportunity(trigger.newMap); } public with sharing class Opportunity_TriggerHelper { @future (callout=true) public static void updateOpportunity (Map<Id, Opportunity> newMap); HttpRequest req = new HttpRequest(); req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx'); req.setMethod('GET'); Http http = new Http(); HTTPResponse res = http.send(req); System.debug(res.getBody()); } } то при сохранении класса получаю ошибку: Error: Compile Error: expecting a right parentheses, found 'http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx' at line 5 column 21 причем если передавать string в качестве параметра то все норм, например так: trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) { String OpportunityId = 'xxxxx'; Opportunity_TriggerHelper.updateOpportunity(OpportunityId); } public with sharing class Opportunity_TriggerHelper { @future (callout=true) public static void updateOpportunity (String OpportunityId) { HttpRequest req = new HttpRequest(); req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id='+OpportunityId); req.setMethod('GET'); Http http = new Http(); HTTPResponse res = http.send(req); System.debug(res.getBody()); } }
В первом куске кода:
public with sharing class Opportunity_TriggerHelper {
@future (callout=true)
public static void updateOpportunity (Map<Id, Opportunity> newMap);
HttpRequest req = new HttpRequest();
req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx');
req.setMethod('GET');Http http = new Http();
HTTPResponse res = http.send(req);
System.debug(res.getBody());
}
}
У тебя в строке public static void updateOpportunity (Map<Id, Opportunity> newMap); в конце стоит ; а должна стоять {
Следующий нюанс
Если ничего не поменялось в последнем релизе то во future нельзя передавать объекты. Только примитивные данные (Integer, String, ID) или списки этих примитивных данных типо List<Id>, Set<Id>
В твоем случае надо из триггера передавать Set<Id>
В первом куске кода: [code] public with sharing class Opportunity_TriggerHelper { @future (callout=true) public static void updateOpportunity (Map<Id, Opportunity> newMap); HttpRequest req = new HttpRequest(); req.setEndpoint('http://dev.xxxxx.com/ntm/trunk/opportunity/remote/sf_query&token=xxxxx&act=update&id=xxxxx'); req.setMethod('GET'); Http http = new Http(); HTTPResponse res = http.send(req); System.debug(res.getBody()); } } [/code] У тебя в строке public static void updateOpportunity (Map<Id, Opportunity> newMap); в конце стоит ; а должна стоять { Следующий нюанс Если ничего не поменялось в последнем релизе то во future нельзя передавать объекты. Только примитивные данные (Integer, String, ID) или списки этих примитивных данных типо List<Id>, Set<Id> В твоем случае надо из триггера передавать Set<Id>
Твой @future метод должен так объявляться
@future (callout=true)
public static void updateOpportunity (Set<Id> opportunityIds){}
Твой @future метод должен так объявляться [code] @future (callout=true) public static void updateOpportunity (Set<Id> opportunityIds){ } [/code]
Вот твой триггер, который передает во @future метод Set<Id> opportunity
trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) {
Set<Id> opportunityIds = new Set<Id>();if (Trigger.isInsert || Trigger.isUpdate) {
opportunityIds = Trigger.newMap.keySet();
}
if (Trigger.isDelete) {
opportunityIds = Trigger.oldMap.keySet();
}Opportunity_TriggerHelper.updateOpportunity(opportunityIds);
}
Ну @future метод сам попробуй написать. Только учти, что тебе на вход будет приходить Set<Id> т.е. ты не знаешь будет 1 или N записей. Так что либо вставляй в запрос только первую opportunityIds[0] или пиши интеграцию, которая может принимать более 1 в одном запросе.
Вот твой триггер, который передает во @future метод Set<Id> opportunity [code] trigger OpportunityRemoteUpdate on Opportunity (after insert, after update, after delete) { Set<Id> opportunityIds = new Set<Id>(); if (Trigger.isInsert || Trigger.isUpdate) { opportunityIds = Trigger.newMap.keySet(); } if (Trigger.isDelete) { opportunityIds = Trigger.oldMap.keySet(); } Opportunity_TriggerHelper.updateOpportunity(opportunityIds); } [/code] Ну @future метод сам попробуй написать. Только учти, что тебе на вход будет приходить Set<Id> т.е. ты не знаешь будет 1 или N записей. Так что либо вставляй в запрос только первую opportunityIds[0] или пиши интеграцию, которая может принимать более 1 в одном запросе.
Осталась маленькая проблема
public static void updateOpportunity (String action, Set<Id> opportunityIds) {
String ids = String.join(opportunityIds, ',');
...
Error: Compile Error: Variable does not exist: String at line 5 column 22 (ругается на String.join)
Осталась маленькая проблема public static void updateOpportunity (String action, Set<Id> opportunityIds) { String ids = String.join(opportunityIds, ','); ... Error: Compile Error: Variable does not exist: String at line 5 column 22 (ругается на String.join)
new List<Id>(your Set instance);
new List<Id>(your Set instance);