You can go from the parent and get the children using a nested SOQL query:
global class YourBatch implements Database.Batchable<sObject>
{
String query;
global YourBatch()
{
// Get evey record from object A and it's related records from object B
query = 'SELECT Id, Name, (SELECT Id, Name FROM CustomObjectB__r) FROM CustomObjectA__c WHERE YourWhereClauseOnobjectA';
}
global Database.QueryLocator start(Database.BatchableContext BC)
{
return Database.getQueryLocator(query);
}
global void execute(Database.BatchableContext BC, List<sObject> scope)
{
// Traverse through the Object A records
for (sObject sObjectA : scope)
{
system.debug((String)sObjectA.get('Name'));
if (sObjectA.getSObjects('CustomObjectB__r') != null)
{
// Traverse through Object B records only related to the current Object A record
for (sObject sObjectB : (List <sObject>)sObjectA.getSObjects('CustomObjectB__r'))
{
system.debug((String)sObjectB.get('Name'));
}
}
}
}
global void finish(Database.BatchableContext BC)
{
// Do something
}
}
Or alternatively you can query the children and get the fields from the parent:
Query:
query = 'SELECT Id, Name, CustomObjectA__r.Name, CustomObjectA__r.OtherField__c FROM CustomObjectB__c WHERE YourWhereClauseOnobjectB';
Execute:
// Traverse through the Object B records
for (sObject sObjectB : scope)
{
system.debug((String)sObjectB.get('Name'));
system.debug((String)sObjectB.get('CustomObjectA__r').get('OtherField__c'));
}