1

There is a weird behaviour when referencing a visualforce page.

I have a screen flow and I'm testing an Apex Action using @InvocableMethod. My method receives a List of Ids, and I use those to get a visualforce renderAs="pdf" that will render content using fields of each record, and insert them as attachments:

    @InvocableMethod(label='Adjuntar PDF')
public static void adjuntarPDF(List<Id> presupuestos){
    List<Attachment> adjuntos = new List<Attachment>();

    for(Id presId : presupuestos){
        System.debug('presupuestoId ====> ' + presId);
        PageReference pdf = Page.PDFPrueba;
        pdf.getParameters().put('id', presId); 
        Attachment adjunto = new Attachment();
        adjunto.Name = 'PDF PRES';
        adjunto.Body = pdf.getContent();
        adjunto.ParentId = presId;
        adjuntos.add(adjunto);
    }

    insert adjuntos;
}

Visualforce controller:

public with sharing class PDFPruebaController {

public String presupuestoId;
public Quote presupuesto {get;set;}

public PDFPruebaController() {
    presupuestoId = ApexPages.currentPage().getParameters().get('id');
    System.debug('presupuestoId visualforce =====> ' + presupuestoId);
    presupuesto = [SELECT Id FROM Quote WHERE Id = :presupuestoId];
}

}

For some reason, when testing the Screen flow, The apex controller throws a List has no rows for assignment error, when executing the query. The thing is, I logged the Id in the controller to see if it was being passed correctly, and it was, according to the logs:

enter image description here

The Id matches what the flow debugger tells me of the created record.

This is happening when debugging and also when trying to execute the flow normally. Is this an unexpected error, or am I missing something?

1
  • 1
    The pdf.getContent() operates outside the current transaction so if the preceding Apex code lines inserted the record the PDFPruebaController would not see it as the transaction containing the insert will not have committed at that point. But I would guess that this is not a problem in flows, though I don't know what the transactional model is for multiple @InvocableMethod calls so perhaps it is a problem...
    – Keith C
    Sep 12, 2022 at 19:01

1 Answer 1

3

PageReference's getContent and getContentAsPDF are treated as callouts. In other words, they happen as a separate, synchronous transaction. As such, a Visualforce page called this way won't be able to see the latest data, which is very likely what's happening here. This is because of transaction isolation, a common feature of many ACID-compliant database systems, including Salesforce.

To fix this, you need to go asynchronous. Add a Pause between the creation of the records and the Apex Action that should read those Id values.

If you read the Triggers and Order of Execution documentation, you'll see that records are given an ID value about half-way through a transaction:

  1. Saves the record to the database, but doesn't commit yet.

This sets some properties, and sets a rollback point, but the ID values here don't exist outside the current transaction. It's not until the entire transaction succeeds successfully that those records are released for other processes (including Visualforce pages) to access.

1
  • Hey ! Thank you a lot for all of this, I didnt know that getContent was treated as a callout, it is very interesting.I couldn't find a Pause element to add to my Screen Flow, but what I did was, modify my Apex Action to start a new transaction (config under Advanced) instead of leaving it to the flow to decide... This did the trick. I'll accept this answer though, as it made me understand the cause of the problem, not just the solution. I appreciate all your help sfdcfox! You are always there to the rescue! Sep 12, 2022 at 19:47

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .