-
ChatterFeed
-
0Best Answers
-
0Likes Received
-
0Likes Given
-
2Questions
-
2Replies
Extracting Information From Nested SOQL Statements in Batch
I am trying to create a batchable program that acts like a roll up helper every night on the account object. In this particular example I am trying to count the number of related activities attached to an account or account child object. I am able to pull my information in a query but when I try to then extract that informaiton I keep getting errors saying the variables I am pulling dont exist. Can someone take a look and see if I have just made a clerical error in my dot notation or someting like that? I am sure the values are returned because ive tested everything in the Query Editor before transitioning it to my code. Here is the program, query and current errors:
APEX CODE:
Current Errors:
APEX CODE:
global class NightlyAccountFieldUpdater implements Database.Batchable<SObject>{
global Database.QueryLocator start(Database.BatchableContext BC){
String query = '[SELECT id, Last_Sales_Contact_Date__c,Next_Sales_Activity_Date__c, OwnerId,';
query += ' (SELECT OwnerId, ActivityDate, ActivitySubType, EndDateTime, IsClosed, IsDeleted, PrimaryWhoId FROM ActivityHistories), ';
query+= ' (SELECT OwnerId, ActivityDate, ActivitySubType, WhoId, WhatId FROM OpenActivities) FROM ACCOUNT]';
return Database.getQueryLocator(query);
}
global static void execute(Database.BatchableContext BC, List<Account> scope){
List<Lead> LeadActivityList = new List<Lead>([SELECT id, Account__c,
(SELECT OwnerId, ActivityDate, ActivitySubType, EndDateTime, IsClosed, IsDeleted,
PrimaryWhoId FROM ActivityHistories),
(SELECT OwnerId, ActivityDate, ActivitySubType, WhoId, WhatId FROM OpenActivities)
FROM LEAD WHERE lead.Account__C != NULL]);
List<Account> masterAccountList = new List<Account>();
Map<Account, List<Activity>> accountActivityMap = new Map<Account, List<Activity>>();
for(SObject tempobj: scope){
Account tempact = new Account(Id = tempobj.Id, OwnerId = tempobj.OwnerId, Last_Sales_Contact_Date__c = tempobj.Last_Sales_Contact_Date__c, Next_Sales_Activity_Date__c = tempobj.Next_Sales_Activity_Date__c);
}
}
global void finish(Database.BatchableContext BC){
}
}
Current Errors:
-
- William Roach 9
- May 15, 2019
- Like
- 0
Cannot get Code Coverage on afterDelete trigger
Hello forum, I am having trouble atchieving 75% code coverage on a trigger im writting and wondered if someone here knows what I am doing incorrectly. I am deleting code and asserting after the fact. Below you can find my trigger as well as the test class and main class. I use a custom testDataFactory to produce my data.
TRIGGER:
MAIN CLASS:
TEST CLASS:
I currently have 56% code coverage on my trigger and 100% coverage on my main class.
TRIGGER:
/**
* ─────────────────────────────────────────────────────────────────────────────────────────────────┐
* Rate Review Attachment Counter Trigger Class
*
* This class is designed to trigger RateReviewAttachmentCounter when the attachment in question is
* related to a Rate_Review__c object
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @author William L. Roach-Barrette <REDACTED>
* @modifiedBy
* @maintainedBy
* @version 1.0
* @created 2019-04-16
* @modified YYYY-MM-DD
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @changes
* vX.X EMAIL
* YYYY-MM-DD Explanation of the change. Multiple lines can be used to explain the change, but
* each line should be indented till left aligned with the previous description text.
*
* vX.X EMAIL
* YYYY-MM-DD Each change to this file should be documented by incrementing the version number,
* and adding a new entry to this @changes list. Note that there is a single blank
* line between each @changes entry.
* ─────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
trigger RateReviewAttachmentTrigger on Attachment (after insert, after update, after delete) {
if(Trigger.isInsert || Trigger.isUpdate){
List<Attachment> approved = new List<Attachment>();
for(Attachment aiq: Trigger.new){
Id parentId = aiq.ParentId;
if(parentId.getSObjectType().getDescribe().getName() == 'Rate_Review__c'){
approved.add(aiq);
}
}
RateReviewAttachmentCounter instance = new RateReviewAttachmentCounter();
instance.attachmentCounter(approved);
}
//when handling a delete you want to pull data from trigger.old and not trigger.new
if(Trigger.isAfter && Trigger.isdelete){
List<Attachment> oldboys = new List<Attachment>();
for(Attachment aiq: Trigger.old){
Id parentId = aiq.ParentId;
if(parentId.getSObjectType().getDescribe().getName() == 'Rate_Review__c'){
oldboys.add(aiq);
}
}
RateReviewAttachmentCounter oldinstance = new RateReviewAttachmentCounter();
oldinstance.attachmentCounter(oldboys);
}
}
MAIN CLASS:
/**
* ─────────────────────────────────────────────────────────────────────────────────────────────────┐
* Rate Review Attachment Counter Main Class
*
* This class is designed to monitor the number of attachments produced and attached to the RateReview
* object. This is to be used so that a salesperson cant create a new ratereview record without asscoiating
* at least one attached review with it.
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @author William L. Roach-Barrette <REDACTED>
* @modifiedBy
* @maintainedBy
* @version 1.0
* @created 2019-04-16
* @modified YYYY-MM-DD
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @changes
* vX.X EMAIL
* YYYY-MM-DD Explanation of the change. Multiple lines can be used to explain the change, but
* each line should be indented till left aligned with the previous description text.
*
* vX.X EMAIL
* YYYY-MM-DD Each change to this file should be documented by incrementing the version number,
* and adding a new entry to this @changes list. Note that there is a single blank
* line between each @changes entry.
* ─────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
public class RateReviewAttachmentCounter{
public void attachmentCounter(List<Attachment> attachList){
List<Rate_Review__c> rrList = new List<Rate_Review__c>();
List<Id> rrIdList = new List<Id>();
List<Attachment> relatedAttachment = new List<Attachment>();
for(Attachment attachy: attachList){
rrIdList.add(attachy.ParentId);
}
rrList = [SELECT id, Number_of_Attachments__c FROM Rate_Review__c WHERE id IN: rrIdList];
relatedAttachment = [SELECT id, parentId FROM Attachment WHERE parentId IN: rrIdList];
for(Rate_Review__c rr: rrList){
Integer attachmentCounter = 0;
id RateReviewId = rr.id;
for(Attachment atch: relatedAttachment){
if(atch.parentId == RateReviewId){
attachmentCounter++;
}
}
rr.Number_of_Attachments__c = attachmentCounter;
}
update rrList;
}
}
TEST CLASS:
/**
* ─────────────────────────────────────────────────────────────────────────────────────────────────┐
* Rate Review Attachment Counter Test Class
*
* This class is designed to test RateReviewAttachmentCounter when the attachment in question is
* related to a Rate_Review__c object
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @author William L. Roach-Barrette <william.roach@pushpay.com>
* @modifiedBy
* @maintainedBy
* @version 1.0
* @created 2019-04-16
* @modified YYYY-MM-DD
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @changes
* vX.X EMAIL
* YYYY-MM-DD Explanation of the change. Multiple lines can be used to explain the change, but
* each line should be indented till left aligned with the previous description text.
*
* vX.X EMAIL
* YYYY-MM-DD Each change to this file should be documented by incrementing the version number,
* and adding a new entry to this @changes list. Note that there is a single blank
* line between each @changes entry.
* ─────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
@isTest
public class RateReviewAttachmentCounterTest {
//The test setup was omitted from this class because governing limits are not a concern when testing and its easier to get direct access to
//produced data then it is to produce the data and querry for it in later tests.
/*@TestSetup
public static void setup(){
TestDataFactory dataGenerator = new TestDataFactory();
Integer numRecords = 1;
List<Rate_Review__c> rrList = new List<Rate_Review__c>(dataGenerator.generateRateReview(numRecords));
System.assert(rrList.size() == numRecords, 'INCORRECT NUMBER OF RECORDS PRODUCED. REQUIRED: ' + numRecords + ' ACTUAL: ' + rrList.size());
}
*/
static testmethod void testAttachmentCounter(){
TestDataFactory dataGenerator = new TestDataFactory();
Integer numRecords = 5;//NumRecords dictates the total number of records produced for testing purposes. Increment for bulk testing and decrement for easy to read logs
List<Rate_Review__c> rrList = new List<Rate_Review__c>(dataGenerator.generateRateReview(numRecords));
System.assert(rrList.size() == numRecords, 'INCORRECT NUMBER OF RECORDS PRODUCED. REQUIRED: ' + numRecords + ' ACTUAL: ' + rrList.size());
System.debug('RATE REVIEW OBJECTS: ' + rrList);
List<Attachment> attachmentList = new List<Attachment>(dataGenerator.generateAttachments(rrList, numRecords));
System.debug('ATTACHMENT LIST: ' + attachmentList);
List<Id> rrIdList = new List<Id>();
for(Rate_Review__c rateReview: rrList){
rrIdList.add(rateReview.id);
}
Test.startTest();
RateReviewAttachmentCounter methodtest = new RateReviewAttachmentCounter();
methodtest.attachmentCounter(attachmentList);
Test.stopTest();
rrList = [SELECT id, Number_of_Attachments__c FROM Rate_Review__c WHERE id IN: rrIdList];
System.assert(rrList.size() == numRecords, 'NOT ENOUGH RATE REVIEWS. EXPECTED: ' + numRecords + ' ACTUAL: ' + rrList.size() );
for(Rate_Review__c rrfinal: rrList){
System.assert(rrfinal.Number_of_Attachments__c == numRecords, 'NUM OF ATTACHMENTS NOT SET');
System.debug('NUMBER OF ATTACHMENTS FIELD: ' + rrfinal.Number_of_Attachments__c);
}
}
static testmethod void testAttachmentCounterDelete(){
Test.startTest();
TestDataFactory dataGenerator = new TestDataFactory();
Integer numRecords1 = 5;//NumRecords dictates the total number of records produced for testing purposes. Increment for bulk testing and decrement for easy to read logs
List<Rate_Review__c> rrList = new List<Rate_Review__c>(dataGenerator.generateRateReview(numRecords1));
System.assert(rrList.size() == numRecords1, 'INCORRECT NUMBER OF RECORDS PRODUCED. REQUIRED: ' + numRecords1 + ' ACTUAL: ' + rrList.size());
System.debug('RATE REVIEW OBJECTS: ' + rrList);
List<Attachment> attachmentList = new List<Attachment>(dataGenerator.generateAttachments(rrList, numRecords1));
System.debug('ATTACHMENT LIST: ' + attachmentList);
List<Id> rrIdList = new List<Id>();
for(Rate_Review__c rateReview: rrList){
rrIdList.add(rateReview.id);
}
RateReviewAttachmentCounter methodtest = new RateReviewAttachmentCounter();
methodtest.attachmentCounter(attachmentList);
delete attachmentList;
Test.stopTest();
rrList = [SELECT id, Number_of_Attachments__c FROM Rate_Review__c WHERE id IN: rrIdList];
System.assert(rrList.size() == numRecords1, 'NOT ENOUGH RATE REVIEWS. EXPECTED: ' + 0 + ' ACTUAL: ' + rrList.size() );
for(Rate_Review__c rrfinal: rrList){
System.assert(rrfinal.Number_of_Attachments__c == 0 , 'NUM OF ATTACHMENTS NOT SET EXPECTED: ' + rrfinal.Number_of_Attachments__c + ' ACTUAL: ' + numRecords1);
System.debug('NUMBER OF ATTACHMENTS FIELD: ' + rrfinal.Number_of_Attachments__c);
}
}
}
I currently have 56% code coverage on my trigger and 100% coverage on my main class.
-
- William Roach 9
- April 29, 2019
- Like
- 0
Cannot get Code Coverage on afterDelete trigger
Hello forum, I am having trouble atchieving 75% code coverage on a trigger im writting and wondered if someone here knows what I am doing incorrectly. I am deleting code and asserting after the fact. Below you can find my trigger as well as the test class and main class. I use a custom testDataFactory to produce my data.
TRIGGER:
MAIN CLASS:
TEST CLASS:
I currently have 56% code coverage on my trigger and 100% coverage on my main class.
TRIGGER:
/**
* ─────────────────────────────────────────────────────────────────────────────────────────────────┐
* Rate Review Attachment Counter Trigger Class
*
* This class is designed to trigger RateReviewAttachmentCounter when the attachment in question is
* related to a Rate_Review__c object
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @author William L. Roach-Barrette <REDACTED>
* @modifiedBy
* @maintainedBy
* @version 1.0
* @created 2019-04-16
* @modified YYYY-MM-DD
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @changes
* vX.X EMAIL
* YYYY-MM-DD Explanation of the change. Multiple lines can be used to explain the change, but
* each line should be indented till left aligned with the previous description text.
*
* vX.X EMAIL
* YYYY-MM-DD Each change to this file should be documented by incrementing the version number,
* and adding a new entry to this @changes list. Note that there is a single blank
* line between each @changes entry.
* ─────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
trigger RateReviewAttachmentTrigger on Attachment (after insert, after update, after delete) {
if(Trigger.isInsert || Trigger.isUpdate){
List<Attachment> approved = new List<Attachment>();
for(Attachment aiq: Trigger.new){
Id parentId = aiq.ParentId;
if(parentId.getSObjectType().getDescribe().getName() == 'Rate_Review__c'){
approved.add(aiq);
}
}
RateReviewAttachmentCounter instance = new RateReviewAttachmentCounter();
instance.attachmentCounter(approved);
}
//when handling a delete you want to pull data from trigger.old and not trigger.new
if(Trigger.isAfter && Trigger.isdelete){
List<Attachment> oldboys = new List<Attachment>();
for(Attachment aiq: Trigger.old){
Id parentId = aiq.ParentId;
if(parentId.getSObjectType().getDescribe().getName() == 'Rate_Review__c'){
oldboys.add(aiq);
}
}
RateReviewAttachmentCounter oldinstance = new RateReviewAttachmentCounter();
oldinstance.attachmentCounter(oldboys);
}
}
MAIN CLASS:
/**
* ─────────────────────────────────────────────────────────────────────────────────────────────────┐
* Rate Review Attachment Counter Main Class
*
* This class is designed to monitor the number of attachments produced and attached to the RateReview
* object. This is to be used so that a salesperson cant create a new ratereview record without asscoiating
* at least one attached review with it.
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @author William L. Roach-Barrette <REDACTED>
* @modifiedBy
* @maintainedBy
* @version 1.0
* @created 2019-04-16
* @modified YYYY-MM-DD
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @changes
* vX.X EMAIL
* YYYY-MM-DD Explanation of the change. Multiple lines can be used to explain the change, but
* each line should be indented till left aligned with the previous description text.
*
* vX.X EMAIL
* YYYY-MM-DD Each change to this file should be documented by incrementing the version number,
* and adding a new entry to this @changes list. Note that there is a single blank
* line between each @changes entry.
* ─────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
public class RateReviewAttachmentCounter{
public void attachmentCounter(List<Attachment> attachList){
List<Rate_Review__c> rrList = new List<Rate_Review__c>();
List<Id> rrIdList = new List<Id>();
List<Attachment> relatedAttachment = new List<Attachment>();
for(Attachment attachy: attachList){
rrIdList.add(attachy.ParentId);
}
rrList = [SELECT id, Number_of_Attachments__c FROM Rate_Review__c WHERE id IN: rrIdList];
relatedAttachment = [SELECT id, parentId FROM Attachment WHERE parentId IN: rrIdList];
for(Rate_Review__c rr: rrList){
Integer attachmentCounter = 0;
id RateReviewId = rr.id;
for(Attachment atch: relatedAttachment){
if(atch.parentId == RateReviewId){
attachmentCounter++;
}
}
rr.Number_of_Attachments__c = attachmentCounter;
}
update rrList;
}
}
TEST CLASS:
/**
* ─────────────────────────────────────────────────────────────────────────────────────────────────┐
* Rate Review Attachment Counter Test Class
*
* This class is designed to test RateReviewAttachmentCounter when the attachment in question is
* related to a Rate_Review__c object
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @author William L. Roach-Barrette <william.roach@pushpay.com>
* @modifiedBy
* @maintainedBy
* @version 1.0
* @created 2019-04-16
* @modified YYYY-MM-DD
* ──────────────────────────────────────────────────────────────────────────────────────────────────
* @changes
* vX.X EMAIL
* YYYY-MM-DD Explanation of the change. Multiple lines can be used to explain the change, but
* each line should be indented till left aligned with the previous description text.
*
* vX.X EMAIL
* YYYY-MM-DD Each change to this file should be documented by incrementing the version number,
* and adding a new entry to this @changes list. Note that there is a single blank
* line between each @changes entry.
* ─────────────────────────────────────────────────────────────────────────────────────────────────┘
*/
@isTest
public class RateReviewAttachmentCounterTest {
//The test setup was omitted from this class because governing limits are not a concern when testing and its easier to get direct access to
//produced data then it is to produce the data and querry for it in later tests.
/*@TestSetup
public static void setup(){
TestDataFactory dataGenerator = new TestDataFactory();
Integer numRecords = 1;
List<Rate_Review__c> rrList = new List<Rate_Review__c>(dataGenerator.generateRateReview(numRecords));
System.assert(rrList.size() == numRecords, 'INCORRECT NUMBER OF RECORDS PRODUCED. REQUIRED: ' + numRecords + ' ACTUAL: ' + rrList.size());
}
*/
static testmethod void testAttachmentCounter(){
TestDataFactory dataGenerator = new TestDataFactory();
Integer numRecords = 5;//NumRecords dictates the total number of records produced for testing purposes. Increment for bulk testing and decrement for easy to read logs
List<Rate_Review__c> rrList = new List<Rate_Review__c>(dataGenerator.generateRateReview(numRecords));
System.assert(rrList.size() == numRecords, 'INCORRECT NUMBER OF RECORDS PRODUCED. REQUIRED: ' + numRecords + ' ACTUAL: ' + rrList.size());
System.debug('RATE REVIEW OBJECTS: ' + rrList);
List<Attachment> attachmentList = new List<Attachment>(dataGenerator.generateAttachments(rrList, numRecords));
System.debug('ATTACHMENT LIST: ' + attachmentList);
List<Id> rrIdList = new List<Id>();
for(Rate_Review__c rateReview: rrList){
rrIdList.add(rateReview.id);
}
Test.startTest();
RateReviewAttachmentCounter methodtest = new RateReviewAttachmentCounter();
methodtest.attachmentCounter(attachmentList);
Test.stopTest();
rrList = [SELECT id, Number_of_Attachments__c FROM Rate_Review__c WHERE id IN: rrIdList];
System.assert(rrList.size() == numRecords, 'NOT ENOUGH RATE REVIEWS. EXPECTED: ' + numRecords + ' ACTUAL: ' + rrList.size() );
for(Rate_Review__c rrfinal: rrList){
System.assert(rrfinal.Number_of_Attachments__c == numRecords, 'NUM OF ATTACHMENTS NOT SET');
System.debug('NUMBER OF ATTACHMENTS FIELD: ' + rrfinal.Number_of_Attachments__c);
}
}
static testmethod void testAttachmentCounterDelete(){
Test.startTest();
TestDataFactory dataGenerator = new TestDataFactory();
Integer numRecords1 = 5;//NumRecords dictates the total number of records produced for testing purposes. Increment for bulk testing and decrement for easy to read logs
List<Rate_Review__c> rrList = new List<Rate_Review__c>(dataGenerator.generateRateReview(numRecords1));
System.assert(rrList.size() == numRecords1, 'INCORRECT NUMBER OF RECORDS PRODUCED. REQUIRED: ' + numRecords1 + ' ACTUAL: ' + rrList.size());
System.debug('RATE REVIEW OBJECTS: ' + rrList);
List<Attachment> attachmentList = new List<Attachment>(dataGenerator.generateAttachments(rrList, numRecords1));
System.debug('ATTACHMENT LIST: ' + attachmentList);
List<Id> rrIdList = new List<Id>();
for(Rate_Review__c rateReview: rrList){
rrIdList.add(rateReview.id);
}
RateReviewAttachmentCounter methodtest = new RateReviewAttachmentCounter();
methodtest.attachmentCounter(attachmentList);
delete attachmentList;
Test.stopTest();
rrList = [SELECT id, Number_of_Attachments__c FROM Rate_Review__c WHERE id IN: rrIdList];
System.assert(rrList.size() == numRecords1, 'NOT ENOUGH RATE REVIEWS. EXPECTED: ' + 0 + ' ACTUAL: ' + rrList.size() );
for(Rate_Review__c rrfinal: rrList){
System.assert(rrfinal.Number_of_Attachments__c == 0 , 'NUM OF ATTACHMENTS NOT SET EXPECTED: ' + rrfinal.Number_of_Attachments__c + ' ACTUAL: ' + numRecords1);
System.debug('NUMBER OF ATTACHMENTS FIELD: ' + rrfinal.Number_of_Attachments__c);
}
}
}
I currently have 56% code coverage on my trigger and 100% coverage on my main class.

- William Roach 9
- April 29, 2019
- Like
- 0