function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
SeanGormanSeanGorman 

Batch Apex Null Object Refernce Issue in Start()

Hi,

 

My first attempt at batching and I am coming up with an error. I have referenced other similar issues but I'm not getting anywhere.

 

Calling from a trigger I have a set of IDs that translate directly to User.Id.

 

 

Trigger:

trigger AddCurrtoTrans on lmscons__Transcript__c (after insert, after update) {
	    /*
	    	adds a curriculum to a transcript when transcript is created
	        need to call a future class to enter a new curriculum assignment record 
	        for each new user added in a given trigger context.
       */

	set<id> setTrainees = new set<id>();
	//string strQuery = '';

	if (trigger.isInsert || trigger.isupdate)
	{
		// filter thoruugh the transcripts to find IDs (future classes cannot take cObjects)
		for (lmscons__Transcript__c lT : trigger.new)
		{
	        setTrainees.add(lT.lmscons__Trainee__c);
	    }
	    system.debug('setTrainees ' + setTrainees);
		//CreateOnBoarding.addCurrtoTrans(setTrainees);
	    //list<User> listTrainees = new list<User>([Select id from User where id in :setTrainees]);

		//RunAssignmentRulesBatch Create = new RunAssignmentRulesBatch(strQuery);
		database.executeBatch(new RunAssignmentRulesBatch(setTrainees), 100 );
	}
}

 

 

Class

global class RunAssignmentRulesBatch implements Database.Batchable<sObject>, Database.Stateful, Database.AllowsCallouts {

	global final string strQuery;
	global final set<id> Trainees;

	public RunAssignmentRulesBatch(set<id> Trainees)
	{
		system.debug('Trainees '+Trainees);
		if (system.Test.isRunningTest()) {
			this.strQuery = 'SELECT Id FROM User WHERE Id = \'' + UserInfo.getUserId() + '\' LIMIT 1';
		}
		else
		{
			strQuery = 'SELECT u.Id, u.Department, u.Division from User u where u.ID in :Trainees and u.ContractorY_N__c = FALSE and u.IsActive=TRUE';
			system.debug('strQuery constructor'+strQuery);
		}
	}

	global Database.QueryLocator start(Database.BatchableContext BC) {
		system.debug('strQuery start'+strQuery);
		return  Database.getQueryLocator(strQuery);
	}

	global void finish(Database.BatchableContext BC) {
	}

	global void execute(Database.BatchableContext BC, list<User> Trainees) {
		system.debug('Trainees in execute '+Trainees);
		addAssignmentBatch(BC, Trainees);
	}
    global void addAssignmentBatch(Database.BatchableContext BC, list<User> Trainees)
    {
        /*

            curr.ass requires:
                curriculum | this will be determined by the lmscons__Transcript__c.lmscons__Trainee__c
                transcript | this is passed in by the trigger
                trainess | this is passed in by the trigger
                Trainees to transcript relationship | this is passed in by the trigger

            Analytic Development On-boarding Program
            Pre-Sales On-boarding Program (retired)
            Product Development On-boarding Program
            Professional Services (PS) On-boarding Program
            PTO On-boarding Program
            PTO On-boarding Program - General
            Quality Assurance On-boarding Program
            Sales On-boarding Program
            Scores Delivery On-boarding Program

        */

        system.debug('Trainees in addAssignmentBatch '+Trainees);

        for (User trainee: Trainees)

 

logfile

14:16:47.047 (47406000)|METHOD_EXIT|[1]|RunAssignmentRulesBatch
14:16:47.047 (47640000)|SYSTEM_METHOD_ENTRY|[21]|System.debug(ANY)
14:16:47.047 (47698000)|USER_DEBUG|[21]|DEBUG|strQuery startSELECT u.Id, u.Department, u.Division from User u where u.ID in :Trainees and u.IsActive=TRUE
14:16:47.047 (47712000)|SYSTEM_METHOD_EXIT|[21]|System.debug(ANY)
14:16:47.047 (47739000)|SYSTEM_METHOD_ENTRY|[22]|Database.getQueryLocator(String)
14:16:47.049 (49583000)|SOQL_EXECUTE_BEGIN|[22]|Aggregations:0|SELECT u.Id, u.Department, u.Division from User u 
14:16:47.051 (51344000)|EXCEPTION_THROWN|[22]|System.NullPointerException: Attempt to de-reference a null object
14:16:47.051 (51562000)|SYSTEM_METHOD_EXIT|[22]|Database.getQueryLocator(String)
14:16:47.051 (51628000)|FATAL_ERROR|System.NullPointerException: Attempt to de-reference a null object
Best Answer chosen by Admin (Salesforce Developers) 
crop1645crop1645

Here is your problem:

 

strQuery = 'SELECT u.Id, u.Department, u.Division from User u where u.ID in :Trainees and u.ContractorY_N__c = FALSE and u.IsActive=TRUE';

 The expression ':Trainees' is not valid dynamic SOQL.   It is, however, valid APEX SOQL and easy to get confused.  You need to blow apart the set<ID> trainees into parenthesized , comma separated, quoted ids like this: ('id1','id2','id3') before insertion into the strQuery string.

 

One way to debug this is to look at the result from:

system.debug('strQuery constructor'+strQuery)

 and paste into SFDC Workbench or Eclipse IDE Schema and try and run the query.  It has to be valid SOQL per the SFDC SOQL Guide

 

Kudos to you for putting debug statements in to try and figure this out yourself before reverting to the boards.

All Answers

crop1645crop1645

Here is your problem:

 

strQuery = 'SELECT u.Id, u.Department, u.Division from User u where u.ID in :Trainees and u.ContractorY_N__c = FALSE and u.IsActive=TRUE';

 The expression ':Trainees' is not valid dynamic SOQL.   It is, however, valid APEX SOQL and easy to get confused.  You need to blow apart the set<ID> trainees into parenthesized , comma separated, quoted ids like this: ('id1','id2','id3') before insertion into the strQuery string.

 

One way to debug this is to look at the result from:

system.debug('strQuery constructor'+strQuery)

 and paste into SFDC Workbench or Eclipse IDE Schema and try and run the query.  It has to be valid SOQL per the SFDC SOQL Guide

 

Kudos to you for putting debug statements in to try and figure this out yourself before reverting to the boards.

This was selected as the best answer
SeanGormanSeanGorman
just coding something now. Putting it in the trigger:
if(setTrainees.size() ==1)
{
strQuery = lT.lmscons__Trainee__c;
}
else
{
strQuery += ', ' +lT.lmscons__Trainee__c;
}
Vadim RudkovVadim Rudkov
Could you provide the full class and logfile?
And BTW running a batch from a trigger is not a very good idea.
SeanGormanSeanGorman

This was resolved by the previous poster. The problem was in the way I built the SOQL.

 

I understand the problems of batching out of a trigger but the volume of traffic in from the trigger is controlled by the integration and not expected to be more than 10-20 user records. The issue is in the amount of data that this causes to be written.

Vadim RudkovVadim Rudkov

Let me say that promlem is not exactly in

strQuery = 'SELECT u.Id, u.Department, u.Division from User u where u.ID in :Trainees and u.ContractorY_N__c = FALSE and u.IsActive=TRUE';

 There is nothing wrong with expressiong ':Trainees'. The problem is that it shoud to be saved in a variable first and it will work fine:

global class RunAssignmentRulesBatch implements Database.Batchable<sObject>{

    global final string strQuery;
    global final set<id> Trainees;

    public RunAssignmentRulesBatch(set<id> Trainees) {
        this.Trainees = Trainees;
        this.strQuery = 'select Id from User where ID in :Trainees';
    }

    global Database.QueryLocator start(Database.BatchableContext BC) {
        return  Database.getQueryLocator(strQuery);
    }

    global void finish(Database.BatchableContext BC) {
    }

    global void execute(Database.BatchableContext BC, list<User> Trainees) {
        system.debug('### ' + Trainees.size());
    }
}