It looks like TMappingExplorerManager isn't working in a thread-safe way:
function TMappingExplorerManager.Get(ModelName: string): TMappingExplorer;
begin
ModelName := LowerCase(ModelName);
if FExplorers.TryGetValue(ModelName, Result) then Exit;
Result := TMappingExplorer.Create(ModelName);
FExplorers.Add(ModelName, Result);
end;
If the application spawns several threads that each created new TObjectManagers without having first having created at least one in the main thread (thus, initializing model), there is a very good chance that the above code will fail: TryGetValue will be false for the first few threads without any of them having had time to reach the FExplorers.Add(ModelName, Result)
That whole section should be protected by a critical section.
The same goes for the way the class variable FExplorerManager: TMappingExplorerManager; of TMappingExplorer is accessed:
class function TMappingExplorer.ExplorerManager: TMappingExplorerManager;
begin
if FExplorerManager = nil then
FExplorerManager := TMappingExplorerManager.Create;
Result := FExplorerManager;
end;
This has a high risk of causing several different TMappingExplorerManager to be created with the reference to all of them but the last one being lost (but still used by calling threads).
This is a problem because TObjectManager isn't thread-safe (which is fine) and therefore needs to be re-created for each concurrent threads. Each of these instances will attempt to access the TMappingExplorerManager singleton in order to obtain its one instance of TMappingExplorer and trigger the race condition.