financialforcedev/fflib-apex-common — pull request #23 by adtennant (2014-08-12 20:22:28+00:00)
Title: Ability for SObjectUnitOfWork to resolve self-relationships

Added the ability to handle self-relationships, e.g.

fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(new Schema.SObjectType[] { Account.SObjectType });
Account parent = new Account(Name = 'Parent');
uow.registerNew(parent);
uow.registerNew(new Account(Name = 'Child'), Account.ParentId, parent);
uow.registerNew(new Account(Name = 'Child'), Account.ParentId, parent);
uow.commitWork(); // inserts parent, then inserts children

This also allows you to process objects in multiple passes, for example:

fflib_SObjectUnitOfWork uow = new fflib_SObjectUnitOfWork(new Schema.SObjectType[] { Account.SObjectType, Custom__c.SObjectType, Account.SObjectType });
Account parent = new Account(Name = 'Parent');
uow.registerNew(parent);

Custom__c custom = new Custom__c();
uow.registerNew(custom, Custom__c.ParentAccountId__c, parent);

Account child = new Account(Name = 'Child');
uow.registerNew(child, Account.ParentId, parent);
uow.registerRelationship(child, Account.CustomId__c, custom);
uow.commitWork(); // inserts parent, then custom, then finally child

This is massively hack-y at the moment, but it works... just about. I'm submitting this pull request early to expose the code to more eyes and to get input on to how I should develop this further.

Known issues:

* Relies on fiddling with the Id field pre-insert, I can't find a better way of doing this whilst still allowing the public interface to work with SObjects
* registerNew must be called in dependency order, i.e. parent before child
* Relies on a custom hashmap implementation to remain performant (although this is due to what I suspect is a platform bug, this reliance can be removed when this is fixed, see: http://salesforce.stackexchange.com/questions/46525/hashcode-is-never-called-when-adding-to-maps-and-sets)
* No error handling, e.g. no reporting of objects whose relationships cannot be resolved