2015-11-12 1 views
0

Bonjour! Je travaille sur un déclencheur dans Salesforce et je continue à rencontrer une erreur que je n'arrive pas à résoudre alors j'espère que quelqu'un avec plus d'expérience peut m'aider à me remettre sur les rails. J'ai traqué Google et j'ai souvent tripoté la structure de mon code, mais je n'arrive pas à trouver un algorithme qui fonctionne.Erreur de mise à jour Salesforce Trigger

Objectif: J'ai été chargé d'écrire un déclencheur qui gérera la logique requise pour gérer les classements de cas par développeur. Chaque développeur est affecté à des cas et ces cas peuvent ou non avoir une priorité déterminée par l'entreprise. Chaque développeur ne peut avoir que 10 cas prioritaires en même temps. Tous les autres cas auront juste une valeur nulle dans le champ de classement. Si un dossier avec un classement est inséré, mis à jour ou supprimé, tous les autres cas affectés à ce développeur avec un classement doivent automatiquement être mis à jour en conséquence. Tout cas avec un rang supérieur à 10 sera annulé. Problème: J'ai terminé l'insertion et la fonctionnalité de déclenchement de suppression. Cette section du code a été testée et elle a fonctionné correctement. Je sais qu'il est possible que mon code ait été mieux écrit, donc j'accepterai toujours des conseils dans ce domaine, mais la principale chose que je veux résoudre est la logique de mise à jour dans le déclencheur.

Erreurs:

  1. Lorsque je tente de mettre à jour un cas avec un rang de valeur nulle de sorte qu'il a maintenant une valeur entre 1-10 Je reçois cette erreur:

There were custom validation error(s) encountered while saving the affected record(s). The first validation error encountered was "Apex trigger CaseRankingTrigger caused an unexpected exception, contact your administrator: CaseRankingTrigger: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 500M0000006sLVOIA2; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = 500M0000006sLVO) is currently in trigger CaseRankingTrigger, therefore it cannot recursively update itself: []: Trigger.CaseRankingTrigger: line 62, column 1".

  1. Lorsque j'essaie de mettre à jour un cas avec un rang existant compris entre 1 et 10 avec un nouveau nombre, j'obtiens cette erreur:

Error: Invalid Data. Review all error messages below to correct your data. Apex trigger CaseRankingTrigger caused an unexpected exception, contact your administrator: CaseRankingTrigger: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 500M0000006sLTrIAM; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, CaseRankingTrigger: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 500M0000006sLUaIAM; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = 500M0000006sLUa) is currently in trigger CaseRankingTrigger, therefore it cannot recursively update itself: [] Trigger.CaseRankingTrigger: line 74, column 1: []: Trigger.CaseRankingTrigger: line 62, column 1

  1. Lorsque je tente de mettre à jour un cas avec un rang existant à une valeur nulle, le cas sera nulle sur, mais les autres cas, les valeurs ne sont pas déplacés vers le bas pour éviter un écart . Cela signifie que si j'ai les cas 1-8 et que je supprime le cas 5, alors les cas 6 7 et 8 devraient être ramenés à 5 6 et 7 respectivement.

code:

trigger CaseRankingTrigger on Case (before insert, before update, before delete) { 
// class level variables 
Integer MAX = 10; 
Integer MIN = 1; 
String dev; 
Decimal oldRank; 
Decimal newRank; 
/*************************************************************************************** 
* This block of code fires if a new Case is being inserted into the database 
***************************************************************************************/ 
if (trigger.isInsert) { 
    // iterates through the Cases in the new trigger 
    for (Case c : trigger.new) { 
     // sets the developer to the developer on the Case 
     dev = c.Resource_Assigned__c; 
     // sets the new rank for the Case being inserted 
     newRank = c.Case_Rank__c; 
     // this block of code only fires if the Case rank field is not null - this allows for Cases with no rank to be inserted without affecting any other Case 
     if (newRank != null) { 
      // populates a list of Cases assigned to the developer if they have a ranking equal to or greater than the rank of the new Case being inserted 
      List<Case> devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND Case_Rank__c >= :newRank]; 
      // iterates over the list of Cases and increases their rank value by 1 to create room for the new Case then inserts that list back into the database 
      for (Case devCase : devCases) { 
       devCase.Case_Rank__c = devCase.Case_Rank__c + 1; 
      } 
      update devCases; 
      // populates a list of Cases for the assigned developer if they have a ranking greater than the highest rank allowed 
      devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND Case_Rank__c > :MAX]; 
      // iterates over the list of applicable Cases with a rank greater than 10 and nulls out the rank value then inserts that list back into the database 
      for (Case devCase : devCases) { 
       devCase.Case_Rank__c = null; 
      } 
      update devCases; 
     } 
    } 
} 
/*************************************************************************************** 
* This block of code fires if an existing Case is being updated 
***************************************************************************************/ 
else if (trigger.isUpdate) { 
    for (Case cOld : trigger.old) { 
     oldRank = cOld.Case_Rank__c; 
    } 
    for (Case c : trigger.new) { 
     dev = c.Resource_Assigned__c; 
     newRank = c.Case_Rank__c; 
     if (oldRank == null && newRank != null) { 
      List<Case> devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND Case_Rank__c >= :newRank]; 
      for (Case devCase : devCases) { 
       devCase.Case_Rank__c = devCase.Case_Rank__c + 1; 
      } 
      update devCases; 
      devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND (Case_Rank__c > :MAX OR Case_Rank__c < :MIN)]; 
      for (Case devCase : devCases) { 
       devCase.Case_Rank__c = null; 
      } 
      update devCases; 
     } else { 
      if (newRank != null) { 
       List<Case> devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND Case_Rank__c >= :newRank]; 
       for (Case devCase : devCases) { 
        devCase.Case_Rank__c = devCase.Case_Rank__c + 1; 
       } 
       update devCases; 
       devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND (Case_Rank__c > :oldRank OR Case_Rank__c < :newRank)]; 
       for (Case devCase : devCases) { 
        devCase.Case_Rank__c = devCase.Case_Rank__c - 1; 
       } 
       update devCases; 
       devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND (Case_Rank__c > :MAX OR Case_Rank__c < :MIN)]; 
       for (Case devCase : devCases) { 
        devCase.Case_Rank__c = null; 
       } 
       update devCases; 
      } 
     } 
    } 
} 
/*************************************************************************************** 
* This block of code fires if an existing Case is deleted from the database 
***************************************************************************************/ 
else if (trigger.isDelete) { 
    // iterates through the Cases in the old trigger 
    for (Case c : trigger.old) { 
     // sets the developer to the developer on the Case 
     dev = c.Resource_Assigned__c; 
     // sets the old rank value for the Case being deleted 
     oldRank = c.Case_Rank__c; 
     // this block of code only fires if the rank field is not null - this allows for Cases with no rank to be deleted without affecting any other Case 
     if (oldRank != null) { 
      // populates a list of Cases assigned to the developer if they have a ranking greater than the rank of the Case being deleted 
      List<Case> devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND Case_Rank__c > :oldRank]; 
      // iterates over the list of applicable Cases and decreases their rank by 1 so there is no gap in rank priority then inserts that list back into the database 
      for (Case devCase : devCases) { 
       devCase.Case_Rank__c = devCase.Case_Rank__c - 1; 
      } 
      update devCases; 
     } 
    } 
} 
/*************************************************************************************** 
* Fall Through 
***************************************************************************************/ 
else {} 

}

J'apprécie vraiment toute aide que vous pouvez me donner tout sur celui-ci!

Cordialement,

Michael


Mise à jour finale: Après avoir utilisé les conseils fournis par @Egor j'ai pu obtenir mon code terminé.

Trigger Code:

/*************************************************************************************** 
* @author:  Michael *REDACTED* 
* @email:  *REDACTED* 
* @date:   11/09/15 
* @brief:   This is a trigger for the Case object that will modify the rank of the Cases 
*      assigned to the developer based on a priority set by the Administrator. 
* @files:   src\classes\CaseRankTriggerHandler.cls 
*      src\classes\CaseRankTriggerHandlerTest.cls 
*      src\layouts\Case-Salesforce Service Ticket.layout 
*      src\objects\Case.object 
*      src\workflows\Case.workflow 
***************************************************************************************/ 
trigger CaseRankTrigger on Case (before insert, before update, before delete) { 
    /* 
    * The CaseRankTriggerHandler constructor method takes (List<Case>, List<Case>, String) 
    */ 
    if (trigger.isInsert) CaseRankTriggerHandler handler = new CaseRankTriggerHandler(trigger.new, trigger.old, 'Insert'); // if a new Case is being inserted into the database 
    if (trigger.isUpdate) CaseRankTriggerHandler handler = new CaseRankTriggerHandler(trigger.new, trigger.old, 'Update'); // if an existing Case is being updated 
    if (trigger.isDelete) CaseRankTriggerHandler handler = new CaseRankTriggerHandler(trigger.new, trigger.old, 'Delete'); // if an existing Case is deleted from the database 
} 

Trigger Handler Code:

/*************************************************************************************** 
* @author:  Michael *REDACTED* 
* @email:  *REDACTED* 
* @date:   11/09/15 
* @brief:   This is a Case object trigger handler class that provides logic to the CaseRankTrigger for manipulating 
*      the ranks of all Cases assigned to a developer based on a priority that is set by an Administrator. 
* @files:   src\classes\CaseRankTrigger.cls 
*      src\classes\CaseRankTriggerHandlerTest.cls 
*      src\layouts\Case-Salesforce Service Ticket.layout 
*      src\objects\Case.object 
*      src\workflows\Case.workflow 
***************************************************************************************/ 
public with sharing class CaseRankTriggerHandler { 
    // class level variables 
    private static Boolean firstRun = true; 
    private static Boolean modify = false; 
    private static Integer MAX = 10; 
    private static Integer MIN = 1; 
    private List<Case> newTrigger {get; set;} 
    private List<Case> currentTrigger {get; set;} 
    private List<Case> cases {get; set;} 
    private List<Case> newList {get; set;} 
    private List<Case> currentList {get; set;} 
    private String developer {get; set;} 
    private Decimal newRank {get; set;} 
    private Decimal currentRank {get; set;} 
    /*************************************************************************************** 
    * @author: Michael *REDACTED* 
    * @email:  *REDACTED* 
    * @date:  11/16/15 
    * @brief:  Class constructor method. 
    * @return:  Void 
    ***************************************************************************************/ 
    public CaseRankTriggerHandler(List<Case> newT, List<Case> oldT, String type) { 
     if (firstRun) { // makes sure that the trigger only runs once 
      firstRun = false; 
      InitializeTrigger(newT, oldT, type); // initializes the trigger 
      if (developer != null) { // skips trigger if DML is performed on a Case with no developer assigned 
       ModificationCheck(type); // determines if Cases need to be modified 
       if (modify) ModificationLogic(type); // modifies Cases if needed 
      } 
     } 
    } 
    /*************************************************************************************** 
    * @author: Michael *REDACTED* 
    * @email:  *REDACTED* 
    * @date:  11/16/15 
    * @brief:  The InitializeTrigger method initializes the handler class based on the type of trigger fired. 
    * @return:  Void 
    ***************************************************************************************/ 
    private void InitializeTrigger(List<Case> newT, List<Case> oldT, String type) { 
     if (type == 'Insert') { 
      this.newTrigger = newT; 
      this.developer = newTrigger[0].Resource_Assigned__c; 
      this.newRank = newTrigger[0].Case_Rank__c; 
      this.newList = [SELECT Subject, CaseNumber, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :developer AND Case_Rank__c != null AND Case_Rank__c = :newRank ORDER BY Case_Rank__c]; 
     } else if (type == 'Update') { 
      this.newTrigger = newT; 
      this.currentTrigger = oldT; 
      this.developer = newTrigger[0].Resource_Assigned__c; 
      this.newRank = newTrigger[0].Case_Rank__c; 
      this.currentRank = currentTrigger[0].Case_Rank__c; 
      this.newList = [SELECT Subject, CaseNumber, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :developer AND Case_Rank__c != null AND Case_Rank__c = :newRank ORDER BY Case_Rank__c]; 
      this.currentList = [SELECT Subject, CaseNumber, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :developer AND Case_Rank__c != null AND Case_Rank__c = :currentRank ORDER BY Case_Rank__c]; 
     } else if (type == 'Delete') { 
      this.currentTrigger = oldT; 
      this.developer = currentTrigger[0].Resource_Assigned__c; 
      this.currentRank = currentTrigger[0].Case_Rank__c; 
     } 
    } 
    /*************************************************************************************** 
    * @author: Michael *REDACTED* 
    * @email:  *REDACTED* 
    * @date:  11/16/15 
    * @brief:  The ModificationCheck method ensures various conditions are met, depending on the type 
    *     of trigger that was fired, before modifying the ranks of the Cases assigned to the developer. 
    * @return:  Void 
    ***************************************************************************************/ 
    private void ModificationCheck(String type) { 
     if (type == 'Insert') { 
      // the Case being inserted has a new rank not equal to null and if the assigned developer already has a Case with the 
      // same rank as the new rank, we will proceed to modification, if not the record will be inserted without modification. 
      if (newRank != null && !newList.isEmpty()) { 
       modify = true; 
      } 
     } else if (type == 'Update') { 
      // if the Case being updated has ranks with different values in both triggers we will proceed to the next check, if not the record is updated without modification. 
      if (newRank != currentRank) { 
       // if the Case being updated has a (new rank equal to null and a current rank not equal to 10) or 
       // if the Case being updated has a new rank not equal to null, we will proceed to the next check, 
       // if not the record is updated without modification. 
       if ((newRank == null && currentRank != 10) || newRank != null) { 
        // if the assigned developer on the Case being updated already has a Case with the same rank as the new or current rank, we will proceed to modification, 
        // if not the record is updated without modification. 
        if (!newList.isEmpty() || !currentList.isEmpty()) { 
         modify = true; 
        } 
       } 
      } 
     } else if (type == 'Delete') { 
      // if the Case being deleted has current rank not equal to null, we will proceed to modification, if not the record is deleted without modification. 
      if (currentRank != null) { 
       modify = true; 
      } 
     } 
    } 
    /*************************************************************************************** 
    * @author: Michael *REDACTED* 
    * @email:  *REDACTED* 
    * @date:  11/16/15 
    * @brief:  If a Case rank needs to be updated the ModificationLogic method calls the appropriate 
    *     computation method based on trigger type and the values of newRank and currentRank. 
    * @return:  Void 
    ***************************************************************************************/ 
    private void ModificationLogic(String type) { 
     if (type == 'Insert') { 
      for (Case c : newTrigger) { 
       // calls the IncreaseCaseRank method and passes it a list of Cases that are assigned to the developer that have a rank greater than or equal to the new rank. 
       IncreaseCaseRank([SELECT Subject, CaseNumber, Case_Rank__c FROM Case WHERE Id NOT IN :newTrigger AND Resource_Assigned__c = :developer AND Case_Rank__c >= :newRank ORDER BY Case_Rank__c]); 
      } 
     } else if (type == 'Update') { 
      for (Case c : newTrigger) { 
       if (currentRank == null) { 
        // if the current rank is null - calls the IncreaseCaseRank method and passes it a list of Cases that are assigned to the developer that have a rank greater than or equal to the new rank. 
        IncreaseCaseRank([SELECT Subject, CaseNumber, Case_Rank__c FROM Case WHERE Id NOT IN :newTrigger AND Resource_Assigned__c = :developer AND Case_Rank__c >= :newRank ORDER BY Case_Rank__c]); 
       } else if (newRank == null) { 
        // if the new rank is null - calls the DecreaseCaseRank method and passes it a list of Cases that are assigned to the developer that have a rank greater than the current rank. 
        DecreaseCaseRank([SELECT Subject, CaseNumber, Case_Rank__c FROM Case WHERE Id NOT IN :newTrigger AND Resource_Assigned__c = :developer AND Case_Rank__c > :currentRank ORDER BY Case_Rank__c]); 
       } else if (newRank > currentRank) { 
        // if the new rank is greater than the current rank - calls the DecreaseCaseRank method and passes it a list of Cases that are assigned to the developer that have a rank less than or equal to the new rank and greater than to the current rank. 
        DecreaseCaseRank([SELECT Subject, CaseNumber, Case_Rank__c FROM Case WHERE Id NOT IN :newTrigger AND Resource_Assigned__c = :developer AND (Case_Rank__c <= :newRank AND Case_Rank__c > :currentRank) ORDER BY Case_Rank__c]); 
       } else if (newRank < currentRank) { 
        // if the new rank is less than the current rank - calls the IncreaseCaseRank method and passes it a list of Cases that are assigned to the developer that have a rank a. 
        IncreaseCaseRank([SELECT Subject, CaseNumber, Case_Rank__c FROM Case WHERE Id NOT IN :newTrigger AND Resource_Assigned__c = :developer AND (Case_Rank__c >= :newRank AND Case_Rank__c < :currentRank) ORDER BY Case_Rank__c]); 
       } 
      } 
     } else if (type == 'Delete') { 
      for (Case c : currentTrigger) { 
       // calls the DecreaseCaseRank method and passes it a list of Cases that are assigned to the developer that have a rank greater than the current rank. 
       DecreaseCaseRank([SELECT Subject, CaseNumber, Case_Rank__c FROM Case WHERE Id NOT IN :currentTrigger AND Resource_Assigned__c = :developer AND Case_Rank__c > :currentRank ORDER BY Case_Rank__c]); 
      } 
     } 
    } 
    /*************************************************************************************** 
    * @author: Michael *REDACTED* 
    * @email:  *REDACTED* 
    * @date:  11/16/15 
    * @brief:  The DecreaseCaseRank method provides the logic required to properly 
    *     decrease or null out the ranks of the Cases assigned the the developer. 
    * @return:  Void 
    ***************************************************************************************/ 
    private void DecreaseCaseRank(List<Case> cases) { 
     // if the list of Cases passed in by the ModificationLogic method isn't empty then it will iterate through the 
     // list and decrease their ranks by 1 or null out the rank if it is not within the acceptable limits (1-10). 
     if (!cases.isEmpty()) { 
      for (Case c : cases) { 
       if (c.Case_Rank__c >= 1 && c.Case_Rank__c <= 10) { 
        c.Case_Rank__c = c.Case_Rank__c - 1; 
       } else { 
        c.Case_Rank__c = null; 
       } 
      } 
      update cases; 
     } 
     return; 
    } 
    /*************************************************************************************** 
    * @author: Michael *REDACTED* 
    * @email:  *REDACTED* 
    * @date:  11/16/15 
    * @brief:  The IncreaseCaseRank method provides the logic required to properly 
    *     increase or null out the ranks of the Cases assigned the the developer. 
    * @return:  Void 
    ***************************************************************************************/ 
    private void IncreaseCaseRank(List<Case> cases) { 
     // if the list of Cases passed in by the ModificationLogic method isn't empty then it will iterate through the 
     // list and increase their ranks by 1 or null out the rank if it is not within the acceptable limits (1-10). 
     if (!cases.isEmpty()) { 
      for (Case c : cases) { 
       if (c.Case_Rank__c >= 1 && c.Case_Rank__c < 10) { 
        c.Case_Rank__c = c.Case_Rank__c + 1; 
       } else { 
        c.Case_Rank__c = null; 
       } 
      } 
      update cases; 
     } 
     return; 
    } 
} 

Répondre

1

Le problème est que vous essayez de mettre à jour le même cas qui ont déjà tiré sur la gâchette.

devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND (Case_Rank__c > :MAX OR Case_Rank__c < :MIN)]; 
     for (Case devCase : devCases) { 
      devCase.Case_Rank__c = null; 
     } 
     update devCases 

Votre instruction select retournera le cas qui a déclenché ce déclencheur ainsi, parce que son Case_Rank__c est nulle et répond donc aux critères. Même avec la sélection que vous exécutez pour la mise à jour des cas avec un rang de 1-10.

Essayez devCases = [SELECT Id, Case_Rank__c FROM Case WHERE Resource_Assigned__c = :dev AND (Case_Rank__c > :MAX OR Case_Rank__c < :MIN) AND Id NOT IN trigger.new];

Découvrez https://help.salesforce.com/apex/HTViewSolution?id=000005278&language=en_US pour une description de l'exception levée

+0

Merci beaucoup! Votre réponse m'a aidé à résoudre mon problème et j'ai pu continuer et terminer mon code, que je montrerai dans une édition de mon message original. Je ne suis pas sûr si cela aurait pu être mieux écrit ou non, mais j'avais l'impression d'avoir couvert chaque cas d'utilisation de manière efficace. Cependant, je suis toujours ouvert aux pourboires si vous en avez. Merci encore! –