(When you ask a question it is best to include the important parts of the code as well, so the community can best understand and help you.)
I'm assuming that the batch is declared as stateful.
I think it fairly clear this is a problem related to you using an SObject as a key in a map. In this context the SObject's state (not its identity) is what matters - it is the hashCode of the SObject that makes the key value work, and this is computed from the internal state of the SObject - which fields are populated and what those fields' values are. Use of a mutable value as a key is generally a bad idea.
The next thing to think about is - just what values do you need in your SObject in order to use it in the second batch? Could you use the SObject IDs, so have a Map<Id, Set<String>>? If you can't, could you create yourself an immutable Apex class with attributes to hold the important field values, have a constructor to initialize it from an SObject of the required type and implement equals and hashCode methods to make it usable as a key in the map?
Sort these out and you'll probably find it all works without having to re-query the data in the second batch at all.
UPDATE based on the related question (see comment from OP); this includes some additional tips and an example of the immutable data object I mentioned, above:
There are some odd typos and spellings plus some unnecessary "global" usages (assuming you are not exporting these batches from a package) and likely an unnecessary statefulness on BatchB (a batch only needs to be stateful if the state is to change between invocation of start and finish; any state you have when you call executeBatch is maintained as-is otherwise).
I suggest you try the following:
public class BatchA implements Database.Batchable<SObject>, Database.Stateful {
private Map<Id, Set<String>> pMap = new Map<Id, Set<String>>();
private Set<String> bigSet = new Set<String>();
public BatchA() {
}
public Database.QueryLocator start(Database.BatchableContext context) {
return Database.getQueryLocator('SomeQuery FROM SobjectA');
}
public void execute(Database.BatchableContext context, List<SobjectA> scope) {
for (SobjectA a : scope) {
Set<String> interests = new Set<String>();
interests.add(a.SomeField_1__c);
interests.add(a.SomeField_2__c);
interests.add(a.SomeField_3__c);
bigSet.addAll(interests);
pMap.put(a.Id, interests);
}
}
public void finish(Database.BatchableContext context) {
// Chain BatchA to BatchB
Database.executeBatch(new BatchB(pMap, bigSet), 200);
}
}
Now BatchB:
public class BatchB implements Database.Batchable<SObject> {
private Map<Id, Set<String>> pMap;
private List<String> bigSet = new List<String>(); // Not used
public BatchB(Map<Id, Set<String>> pMap, Set<String> bigSet) {
// Done this way to perform type conversion and no other reason
this.bigSet.addAll(bigSet);
// You don't need to worry about changes to the pMap in the BatchA
// context - BatchA changing the pMap after the Database.executeBatch
// would have no impact because BatchB gets serialized to the database
// at the time Database.executeBatch is called and gets deserialized
// asynchronously at some later point
this.pMap = pMap;
}
public Database.QueryLocator start(Database.BatchableContext context) {
return Database.getQueryLocator('SomeQuery FROM SobjectB');
}
public void execute(Database.BatchableContext context, List<SobjectB> scope) {
System.debug('pMap values => ' + pMap); // Demonstrates the full content of the pMap
for (SobjectB b : scope) {
// Try to avoid nested loops - these are really inefficient in Apex. If
// possible with the required logic use a first loop to turn some data
// into an appropriate map then have a second (not nested) loop that
// iterates the target data using map queries to get the relevant data
for (Id curPmap : pMap.keySet()) {
System.debug(pMap.get(curPmap)); // Shows the content of the entry for the current ID, repeatedly for every ID and every "b" instance
}
}
public void finish(Database.BatchableContext context) {
}
}
There is nothing in the code you provided that would cause the pMap to be emptied in BatchB between the first and subsequent chunks. However, since you had it Stateful, if you happened to have some code that you called from BatchB taking the Set<String> obtained from the pMap ("pMap.get(curPmap)" in the code above) where it then called theSet.clear(), the emptied set would be re-persisted along with the map at the end of execute, so on the next iteration it would be a map full of empty sets.
If that is the only reason I would say it is still worth ditching the use of SobjectA as the map key - we know, from the context of use, every one of those SobjectA instances will already have an ID, so the ID is a good way to identify the detail for each instance. If you want other values out of the SobjectA instances for later, you could add something like:
public class SobjectAData {
Id id { public get; private set }
SomeType someValueOfInterest { public get; private set }
SomeOtherType someOtherValue { public get; private set }
public SobjectAData(SobjectA a) {
id = a.Id;
someValueOfInterest = a.Some_Field__c;
someOtherValue = a.Some_Other_Field__c;
}
public Integer hashCode() {
return id.hashCode();
}
public Boolean equals(Object obj) {
if (obj instanceof SobjectAData) {
SobjectAData other = (SobjectAData) obj;
return (id.equals(other.id));
}
return false;
}
}
This implementation assumes that only the ID is relevant for use as a key in any map were this class to be used in that way. This may or may not be reasonable depending on how it is to be used.
Anyway, you could then maintain this data in BatchA, with a member like:
private Map<Id, SobjectAData> aData = new Map<Id, SobjectAData>();
Adding data to this map in BatchA is easy:
aData.put(a.Id, new SobjectAData(a));
You could then pass this data to BatchB via its constructor as needed.
I think this answer covers all the bases. Let me know if I missed anything.