2

この Salesforce.com トリガーを記述する構文 (およびおそらくロジック) に行き詰まっています。Opportunity の ContactRoles にプライマリ コンタクトがリストされているかどうかを確認するトリガーが必要です。プライマリがリストされている場合は、対応する連絡先から LeadSource を検索し、その値を Opportunity の Lead Source に挿入する必要があります。

ヒントやヒントは大歓迎です!

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; }
}
}
4

2 に答える 2

1

あなたのコードには、深刻な問題がいくつかあります。気分を害しないことを願っています。それは素晴らしい要件であり、学習の機会でもあります...

  1. after insertここでは意味がありません。定義上、この Opportunity の挿入を終了したばかりの場合、まだ連絡先の役割はありません。*
  2. after updateOKっぽいです。before update値を入力するだけで、データベースに無料で保存できるため、より良いでしょう。
  3. このロジックを OpportunityContactRole の同様のトリガーに複製する必要があるかもしれません。コードを複製する代わりに、両方の場所から呼び出すことができるクラスを使用しますか?
  4. LeadSourceOpportunityがnullになる場合にのみ、入力したいと思いますか?
  5. ループ内に選択があります。これは非常に悪い習慣です ;) トリガーは「一括」ではありません。最大 20 の制限があるため、誰かが 1 つのトランザクションで (たとえば、データ ローダを使用して) 10 件の商談を更新すると、失敗する可能性があります。トリガーでのクエリ。
  6. ORDER BYなどは必要ありませんLIMIT 1。Salesforce があなたを保護し、1 人の連絡先のみがプライマリになることを許可します。そんな間違いをData Loaderで読み込んでしまいたくても。
  7. Salesforce でリレーションシップがどのように機能するかについて読むと役立つようです。「ドット表記」とサブクエリは、通常の SQL 言語と比べると少し奇妙に見えますが、これらを使用してコードを大幅に簡素化できます。過去にオブジェクト指向プログラミングを行ったことがある場合に役立ちます。ここにいくつかのガイドがあり、ここに公式ドキュメントがあります

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.
}

  • 高度なシナリオの場合は、#1 に細字 ;) 別の挿入後トリガーがあれば、保存直後に連絡先ロールを作成できます...しかし、それは非常に面倒です (どのトリガーが最初に起動したかによって異なります)。本当に興味深いランダムな動作が得られると思います。デバッグを頑張ってください)。特定のオブジェクトに同じ起動キーワードを持つ複数のトリガーがある場合は、トリガーを 1 つだけにして、アクションの順序を完全に制御することをお勧めします。詳細については、 http://www.embracingthecloud.com/2010/07/08/ASimpleTriggerTemplateForSalesforce.aspxを参照してください。

#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 が入力されている場合はスキップする」を残していれば問題ありませんが、それでも 2 つのことを調べたいと思うかもしれません:

  • クラスでいくつかのヘルパー静的フラグを使用し、それを「skipTriggerOnOpps」と呼びます。OpportunityContactRoles のトリガーでこのフラグを設定し、Opportunity トリガーのコード全体をラップして、すでにリード ソースの同期を処理している場合は実行されないようにします。 .
  • 理論的には、何も変更せずに商談に「触れる」ことができます (この場合、不要な副作用ではなく、古いトリガーを利点として扱います)。私にとっては少し魔法のように見えますが、ここで何が起こっているのかについて十分にコメントされている場合、コードの削減、ロジックの重複の削減、単体テストの削減につながる可能性があります...トリガーである限り機能する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
        }
    }
    
于 2012-12-05T19:56:20.927 に答える
0

eyescream のオポチュニティ トリガーは最も役に立ち、問題を解決しています。ただし、OpportunityContactRole がトリガーするという彼の仮説は、残念ながら SFDC ではまだサポートされていないことを指摘しておく価値があります。このアイデア ( https://success.salesforce.com/ideaview?id=08730000000BrdvAAC ) が指摘しているように、OCR でのトリガーは現時点では不可能です。

于 2013-12-18T11:28:53.477 に答える