Closed AllanOricil closed 2 years ago
Hi @AllanOricil You would only want to call the commit method once. Do I understand it correctly that you want insert the record as new, which will cause a trigger to do some stuff based on the "new" status, and then after that you want that same record updated to "Published"?
Shouldn't you make one trigger action that takes any record with status "new" and perform a "Publish" operation on those records, which has a step at the end to set the status to "Published"? Wouldn't that be a cleaner soluation?
Alternatively you could add a separate IDoWork implementation, something like:
MYCUSTOMOBJECT c = new MYCUSTOMOBJECT(Status__c = 'New');
uow.registerNew(c);
uow.registerWork(new MakeMePublished(c));
...
uow.commit();
private class MakeMePublished implements fflib_SObjectUnitOfWork.IDoWork
{
private SObject record;
public MakeMePublished(SObject record)
{
this.record = record;
}
public void doWork()
{
record.put(MyCustomObject.Status__c, 'Published');
update record;
}
}
@wimvelzeboer I start with Status = New because there are other Objects that are going to be inserted in the 1St Commit. I can only change it to "Publish" after these objects are inserted. I put a more complete example bellow. Would your suggestion still work?
fflib_ISObjectUnitOfWork uow = DSP_Application.UnitOfWork.newInstance();
MYFIRSTCUSTOMOBJECT first = new MYFIRSTCUSTOMOBJECT(Status__c = 'New');
uow.registerNew(first);
MYSECONDCUSTOMOBJECT second = new MYSECONDCUSTOMOBJECT();
uow.registerNew(
second,
MYSECONDCUSTOMOBJECT.MYCUSTOMOBJECT__c,
MYCUSTOMOBJECT
);
MYTHIRDDCUSTOMOBJECT third = new MYTHIRDDCUSTOMOBJECT();
uow.registerNew(
third,
MYTHIRDDCUSTOMOBJECT.MYCUSTOMOBJECT__c,
MYTHIRDDCUSTOMOBJECT
);
//After insert MYSECONDCUSTOMOBJECT AND MYTHIRDDCUSTOMOBJECT , MYFIRSTCUSTOMOBJECT is updated with some changes. Then when I set MYFIRSTCUSTOMOBJECT.Status__c = 'Publish' a platform event is Dispatched
uow.commit();
fflib_ISObjectUnitOfWork uow2 = DSP_Application.UnitOfWork.newInstance();
uow2.registerDirty(new MYFIRSTCUSTOMOBJECT(Id = c.Id, Status__c = 'Publish'));
uow2.commit();
@AllanOricil the IDoWork is run at the very end of the UnitOfWork, so when all the insert & update operations (including the trigger logic) has been executed.
So, the implementation of IDoWork should work for you.
@wimvelzeboer amazing. Thanks man for your help :D
@wimvelzeboer one last question. Would you add this private class in the Service Class, where the transaction happens?
@AllanOricil Yes, that would make the most sense to add the IDoWork implementation as a private sub-class.
@wimvelzeboer it works! Thanks again
@wimvelzeboer why on the History there is no change from New -> Publish ?
I was expecting
New -> Publish -> Published
or
New -> Publish -> Error
Like, there is a trigger that when we change to Publish, a Platform Event is dispatched and if it was published, the Status is changed to Published, if it wasn't, the Status is updated to Error.
If you are changing status to publish and then to Published all in the same context, then it would show only the latest updated. Remember, the UOW does the commit work but the actual transaction boundary spans the entire process context; regardless of how many UOWs you have.
Looking at your original question, I would do the following (and changing to use standard objects)
Account a = new Acount(Name = 'foo');
uow.registerNew(a);
Contact c = new Contact(lastName = 'bar')
uow.registerNew(c,Contact.AccountId,a);
a.Status__c = 'updated';
uow.commitWork();
If you have the object references available, you can update the values at any point before the commitWork()
Otherwise, the two {uow object : commitWork()} pairs is perfectly fine as it resolves to effectively this:
insert a;
// set c.AccountId = a.Id;
insert c;
update a;
all in one transaction
I have a feature which I have to do an Update after an Insertion, on the same Transaction.
Basically I insert a Record with Status = 'New' then I relate a bunch of other Objects to this Record then I finally need to update this Record Status to 'Publish'
I was previously doing this Update in a Batch, but I must remove this batch and do it in the same transaction as I don't care if it will work or not.
I tried the code below and it didnt work
then I tried creating a second Unit of Work (uow2) and it worked.
I think the problem is that after a commit, the State is not reset, which means if I call commit again it will try to commit everything that was registered as new or dirty again. Maybe you could reset the UOW state after a Commit, so if I call commit again it will be like a brand new UOW.