I believe this is the type of thing that you need to do which I was trying to explain in comments and apparently not doing a very good job of doing. The database.upsert(list<sObject>,true)
requires that all records be either inserted or updated in order for there to be success.
Whether or not you choose to get the record Id's is entirely your choice. As you can see, at any point at which you've failed to successfully upsert all your records, you automatically do a rollback. You can add an Apex.Page Messages at that point if you desire to.
Using this method, there's no need for a try-catch block. The method assumes the use of lists and would need to be modified if you're using individual records.
Note: Edited to correct locations of 1st and 3rd Database.rollbacks
.
private void save() {
// Note: Provide ACID behavior
Savepoint toBeforeState = Database.setSavepoint();
if(record.IsEmpty() == false)
{
list<Database.UpsertResult>uResults = Database.upsert(record, true);
// Iterate through each returned result
for (Database.uResults ur : urList)
{
if (ur.isSuccess())
{
// Operation was successful, so get the ID of the record that was processed
System.debug('Successfully inserted record. record ID: ' + ur.getId());
}else{
// Operation failed, so get all errors
for(Database.Error err : ur.getErrors())
{
System.debug('The following error has occurred.');
System.debug(err.getStatusCode() + ': ' + err.getMessage());
System.debug('record fields that affected this error: ' + err.getFields());
}
Database.rollback(toBeforeState);
}
}
}
if(ChildrenOfTypeA.IsEmpty() == false)
{
list<Database.upsertResult>uResultsA = Database.upsert(ChildrenOfTypeA, true);
// Iterate through each returned result
for (Database.uResultA urA : urListA)
{
if (urA.isSuccess()) {
// Operation was successful, so get the ID of the record that was processed
System.debug('Successfully inserted record. record ID: ' + urA.getId());
}else {
// Operation failed, so get all errors
for(Database.Error err : urA.getErrors())
{
System.debug('The following error has occurred.');
System.debug(err.getStatusCode() + ': ' + err.getMessage());
System.debug('record fields that affected this error: ' + err.getFields());
}
Database.rollback(toBeforeState);
}
}
}
if(ChildrenOfTypeB.IsEmpty() == false)
{
list<Database.upsertResult>uResultsB = Database.upsert(ChildrenOfTypeB, true);
// Iterate through each returned result
for (Database.uResultA urB : urListB)
{
if (urB.isSuccess())
{
// Operation was successful, so get the ID of the record that was processed
System.debug('Successfully inserted record. record ID: ' + urB.getId());
}else {
// Operation failed, so get all errors
for(Database.Error err : urB.getErrors())
{
System.debug('The following error has occurred.');
System.debug(err.getStatusCode() + ': ' + err.getMessage());
System.debug('record fields that affected this error: ' + err.getFields());
}
Database.rollback(toBeforeState);
}
}
}
}