Triggers 请帮助我将触发器转换为批处理顶点

Triggers 请帮助我将触发器转换为批处理顶点,triggers,salesforce,apex-code,apex,Triggers,Salesforce,Apex Code,Apex,请帮助我将后触发器转换为批处理顶点。 此触发器在opportunity stage更改为“赢得”时触发。 它遍历行项目并检查forecastcustom对象是否与该acint一起存在。如果是,iit将链接到它们。如果不是,itt将创建一个新的Forecast 我的触发器对一些记录运行良好。但要批量更新,我遇到了超时错误。所以选择batch apex,但我从未编写过。请帮助我 trigger Accountforecast on Opportunity (after insert,after up

请帮助我将后触发器转换为批处理顶点。 此触发器在opportunity stage更改为“赢得”时触发。 它遍历行项目并检查forecastcustom对象是否与该acint一起存在。如果是,iit将链接到它们。如果不是,itt将创建一个新的Forecast

我的触发器对一些记录运行良好。但要批量更新,我遇到了超时错误。所以选择batch apex,但我从未编写过。请帮助我

trigger Accountforecast on Opportunity (after insert,after update) {
    List<Acc_c> AccproductList =new List<Acc_c>();
    List<Opportunitylineitem> opplinitemlist =new List<Opportunitylineitem>();
    list<opportunitylineitem > oppdate=  new list<opportunitylineitem >();
    List<Acc__c> accquery =new List<Acc__c>();
    List<date> dt =new List<date>();
    Set<Id> sProductIds = new Set<Id>();
    Set<Id> sAccountIds = new Set<Id>();
    Set<id> saccprodfcstids =new set<Id>();
    Acc__c accpro =new Acc__c();
    string aname;
    Integer i;
    Integer myIntMonth;
    Integer myIntyear;
    Integer myIntdate;

    opplinitemlist=[select Id,PricebookEntry.Product2.Name,opp_account__c,Opp_account_name__c,PricebookEntry.Product2.id, quantity,ServiceDate,Acc_Product_Fcst__c  from Opportunitylineitem                      WHERE Opportunityid IN :Trigger.newMap.keySet() AND Acc__c=''];

    for(OpportunityLineItem oli:opplinitemlist) {
    sProductIds.add(oli.PricebookEntry.Product2.id);
    sAccountIds.add(oli.opp_account__c);
    }
    accquery=[select id,Total_Qty_Ordered__c,Last_Order_Qty__c,Last_Order_Date__c,Fcst_Days_Period__c  from Acc__c where Acc__c.product__c In :sproductids and Acc__c.Account__c in :saccountids]; 

  for(Acc__c apf1 :accquery){
    saccprodfcstids.add(apf1.id);
    }        
    if(saccprodfcstids!=null){
    oppdate=[select servicedate from opportunitylineitem where Acc__c IN :saccprodfcstids ];

    i =[select count() from  Opportunitylineitem where acc_product_fcst__c in :saccprodfcstids];
    }


     for(Opportunity opp :trigger.new)
     {
         if(opp.Stagename=='Closed Won')
         {
                 for(opportunitylineitem opplist:opplinitemlist)
                 {
                     if(!accquery.isempty())
                     {
                         for(opportunitylineitem opldt :oppdate)
                         {
                             string myDate = String.valueOf(opldt);
                             myDate = myDate.substring(myDate.indexof('ServiceDate=')+12);
                             myDate = myDate.substring(0,10);                                    
                             String[] strDate = myDate.split('-');
                             myIntMonth = integer.valueOf(strDate[1]);
                             myIntYear = integer.valueOf(strDate[0]);
                             myIntDate = integer.valueOf(strDate[2]);
                             Date d = Date.newInstance(myIntYear, myIntMonth, myIntDate);
                             dt.add(d);
                         }  
                             dt.add(opp.closedate);
                             dt.sort();                   
                             integer TDays=0;
                             system.debug('*************dt:'+dt.size());
                                 for(integer c=0;c<dt.size()-1;c++)
                                 {
                                     TDays=TDays+dt[c].daysBetween(dt[c+1]);

                                 }
                                 for(Acc_product_fcst__c apf:accquery)
                                 {
                                     apf.Fcst_Days_Period__c = TDays/i;
                                     apf.Total_Qty_Ordered__c =apf.Total_Qty_Ordered__c +opplist.quantity;
                                     apf.Last_Order_Qty__c=opplist.quantity;
                                     apf.Last_Order_Date__c=opp.CloseDate ;
                                     apf.Fcst_Qty_Avg__c=apf.Total_Qty_Ordered__c/(i+1);
                                     Opplist.Acc__c =apf.Id;  
                                 }
                                                    }

                                 else{
                                 accpro.Account__c=opplist.opp_account__c;
                                 accpro.product__c=opplist.PricebookEntry.Product2.Id;
                                 accpro.opplineitemid__c=opplist.id;
                                 accpro.Total_Qty_Ordered__c =opplist.quantity;
                                 accpro.Last_Order_Qty__c=opplist.quantity;
                                 accpro.Last_Order_Date__c=opp.CloseDate;
                                 accpro.Fcst_Qty_Avg__c=opplist.quantity;
                                 accpro.Fcst_Days_Period__c=7;
                                 accproductList.add(accpro);



                                 }
                                 }

             }
         }
         if(!accproductlist.isempty()){
         insert accproductlist;
         }
         update opplinitemlist;
         update accquery;         
     }

首先,你应该看看这个:

一旦您对批次的工作方式有了更好的了解,我们需要考虑以下几点:

确定需要更多处理的对象。账户机会 是否应跨批处理调用维护数据?有状态的? 在性能方面使用正确的数据结构。地图,名单

从代码中,我们可以看到您有三个对象:OpportunityLineItems、Accounts和Opportunity。您的帐户对象似乎在这里使用最多的处理

看起来你只是在跟踪日期,没有做任何聚合。因此,不需要跨批处理调用维护状态

您的代码有可能达到调控器限制,特别是堆上的内存限制。您有一个四嵌套循环。我们的建议是在地图中而不是在列表中维护与商机相关的商机行项目。另外,我们可以通过如下重构代码来消除那些不必要的for循环:

注意:这只是您需要构建的批处理的模板

globalglobal Database.QueryLocator start(Database.BatchableContext BC) class AccountforecastBatch implements Database.Batchable<sObject>
{
    global Database.QueryLocator start(Database.BatchableContext BC)
    {
       // 1. Do some initialization here: (i.e. for(OpportunityLineItem oli:opplinitemlist) {sProductIds.add(oli.PricebookEntry.Product2.id)..}
       // 2. return Opportunity object here:  return Database.getQueryLocator([select id,Total_Qty_Ordered__c,Last_Order_Qty ....]);
    }

    global void execute(Database.BatchableContext BC, List<sObject> scope)
    {
       // 1. Traverse your scope which at this point will be a list of Accounts
       // 2. You're adding dates inside the process for Opportunity Line Items. See if you can isolate this process outside the for loops with a Map data structure.
       // 3. You have 3 potential database transactions here (insert accproductlist;update opplinitemlist; update accquery; ). Ideally, you will only need one DB transaction per batch.If you can complete step 2 above, you might only need to update your opportunity line items. Otherwise, you're trying to do more than one thing in a method and you will need to redesign your solution           
    }

    global void finish(Database.BatchableContext BC) 
    {
       // send email or do some other tasks here
    }
}

这是我写的,但不确定这是否有效以及如何测试。请指导我