我坚持编写这个Salesforce.com触发器的语法(也许是逻辑)。我希望触发器检查是否在商机的ContactRoles中列出了主要联系人。如果列出了主要内容,我需要从相应的联系人中查找LeadSource,并将该值插入商机的主要来源。
非常感谢任何提示或提示!
trigger UpdateContactLeadSource on Opportunity (after insert, after update) {
//Declare the Lead Source Variable which will hold the contact's lead source
string leadsource;
// See if there is a primary contact listed on the Opportunity
for (Opportunity o : Trigger.new) {
OpportunityContactRole[] contactRoleArray =
[select ContactID, isPrimary from OpportunityContactRole where OpportunityId = :o.id ORDER BY isPrimary DESC, createdDate];
// If the there is a primary contact, then...
if (contactRoleArray.size() > 0) {
// Lookup ContactID on the Contacts table to find the lead source
for (Contact contact : [SELECT LeadSource FROM Contact WHERE Contact.Id = :OpportunityContactRole.ContactId LIMIT 1])
// Store the actual lead source in the leadsource variable
{ Contact.LeadSource = leadsource;}
update Opportunity.LeadSource = leadsource; }
}
}
答案 0 :(得分:1)
您的代码中有几个非常糟糕的东西。希望你不会觉得被冒犯,这是一个很好的要求和学习机会......
after insert
在这里没有任何意义。根据定义,如果您刚刚完成插入此商机,它将不会有任何联系人角色。* after update
是好的。 before update
会更好,因为您只需填写该值,您就可以免费保存到数据库。LeadSource
为空时填写它?ORDER BY
,LIMIT 1
等 - Salesforce会保护您并且只允许1个联系人成为主要联系人。即使你想用Data Loader加载它们也是如此。TL; DR
trigger fillLeadSource on Opportunity (before update) {
/* I'm assuming you want to fill LeadSource in only if it was blank.
If that's not the case - just delete this first part of code and in the query instead of ":oppsToFill" bind to ":trigger.new" or
":trigger.newMap.keyset()".
(I know they look weird but you can do it, bind objects/collections in queries that expect Ids / collections of Ids)
*/
Set<Id> oppsToFill = new Set<Id>();
for(Opportunity o : trigger.new){
if(o.LeadSource == null) {
oppsToFill.add(o.Id);
}
}
// Now we'll select all possible contacts wasting only 1 query.
if(!oppsToFill.isEmpty()){
List<OpportunityContactRole> roles = [SELECT OpportunityId, Contact.Name, Contact.LeadSource
FROM OpportunityContactRole
WHERE isPrimary = true AND Contact.LeadSource != null AND OpportunityId IN :oppsToFill];
if(!roles.isEmpty()){
for(OpportunityContactRole ocr : roles){
Opportunity oppToBeFilled = trigger.newMap.get(ocr.OpportunityId);
System.debug('Changing lead source on ' + oppToBeFilled.Name + ' from ' + oppToBeFilled.LeadSource + ' to ' + ocr.Contact.LeadSource + ' (thx to ' + ocr.Contact.Name + ' being the Primary Contact).');
oppToBeFilled.LeadSource = ocr.Contact.LeadSource;
}
}
}
// That's it. If there was a primary contact with Lead source, data will be copied over.
// If there was no primary contact or he didn't have the source filled in - tough luck, we did our best.
// Since it's before update, you get save to database for free.
}
编辑回复评论#3
中的问题在新触发器中你需要类似但不相同的代码(在这种情况下,无论是before
还是after
都无关紧要 - 我们需要明确更新机会)。这里有点糟糕,因为您想要查看的字段不能直接使用 - 您可以访问OpportunityId,ContactId但不能访问Contact.LeadSource。这样的事情可以解决问题:
trigger ContactRoleRollup on OpportunityContactRole(after insert, after update){
Map<Id,Id> oppToContactMap = new Map<Id, Id>();
for(OpportunityContactRole ocr : trigger.new){
if(ocr.isPrimary){
oppToContactMap.put(ocr.OpportunityId, ocr.ContactId);
}
}
if(!oppToContactMap.isEmpty()){
List<Opportunity> oppsToUpdate = [SELECT Id FROM Opportunity WHERE LeadSource = null AND Id IN :oppToContactMap.keyset()];
Map<Id, Contact> contacts = [SELECT Id, LeadSource FROM Contact WHERE LeadSource != null AND Id IN :oppToContactMap.values()];
for(Opportunity o : oppsToUpdate){
Id contactId = oppToContactMap.get(o.Id);
Contact c = contacts.get(contactId);
if(c != null){
o.LeadSource = c.LeadSource;
}
}
update oppsToUpdate;
}
}
这里很有趣,因为这次更新将触发我们对机会的旧触发器。如果你离开我的“跳过,如果填充了leadSource”,那应该没问题,但你仍然想要探索两件事:
从理论上讲,你可以在不改变任何东西的情况下“触摸”机会(将旧触发器视为一种好处,在这种情况下不会产生不必要的副作用)。对我而言,它看起来有点太神奇,但如果它评论了这里发生了什么,它可能会导致更少的代码,更少的逻辑重复,更少的单元测试......只要after
触发它就会工作我们刚刚修改过的联系人角色查询会看到新值。它必须看起来像那样
trigger ContactRoleRollup on OpportunityContactRole(after insert, after update){
Set<Id> oppIds = new Set<Id>();
for(OpportunityContactRole ocr : trigger.new){
if(ocr.isPrimary){
oppIds.add(ocr.OpportunityId);
}
}
if(!oppIds.isEmpty()){
update [SELECT Id FROM Opportunity WHERE LeadSource = null AND Id IN :oppIds];
// That's it. Call update directly on returned list without changing anything, let the other trigger worry about the logic
}
}
答案 1 :(得分:0)
eyecream的机会触发器是最有帮助的并且正在为我解决问题。值得指出的是,不幸的是,SFDC尚未支持OpportunityContactRole触发他的假设。正如这个想法(https://success.salesforce.com/ideaview?id=08730000000BrdvAAC)所指出的那样,目前无法在OCR上触发。