1

I have some Apex code written to create a new Account, and then create a new Library (ContentWorkspace) and new Folder (ContentFolder) within that Library to house assets for that Account. It appears that one of these Content objects is a "non-setup" object, so the following error is being thrown: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): ContentFolder, original object: ContentWorkspace: []

Here is the code I have written to accomplish this:

// create Account
Account acc = new Account();
acc.Name = 'Test';
insert acc;

// create Library
ContentWorkspace workspace = new ContentWorkspace();
workspace.Name = 'Test';
insert workspace;

// create Folder within that Library
workspace = [select Id from ContentWorkspace where Name =: 'Test'];
ContentFolder parentFolder = [select Id from ContentFolder where Name =: workspace.Id];
ContentFolder folder = new ContentFolder();
folder.Name = 'Test';
folder.ParentContentFolderId = parentFolder.Id;
insert folder;

Am I missing something? Or is this just not possible to sequentially do like this in Apex? The only "workaround" for this DmlException I found online was to make the DML operation for the "non-setup" object in a @future method. This won't work because I need the Library to exist in order to properly parent the Folders, so if the Library creation is in a @future method, the Folder creation code won't work since the Library doesn't exist yet.

4
  • Isn't it just the fact that you create an Account first? Why not just create that asynchronously?
    – Adrian Larson
    Apr 27, 2021 at 21:17
  • No, this error still occurs even if you remove the Account creation piece. It appears that ContentWorkspace is a "setup" object but ContentFolder is not.
    – OhlPatrol
    Apr 27, 2021 at 21:23
  • Clarification, is this in an Apex unit test or actual production code?
    – David Reed
    Apr 27, 2021 at 21:30
  • Actual code, not a test class.
    – OhlPatrol
    Apr 27, 2021 at 21:31

1 Answer 1

0

One route to do this is to bounce through a Queueable chain to maintain your state while you separate the manipulation of setup and non-setup objects into separate transactions. Here's a sketch of what that could look like:

public class ContentQueueable implements Queueable {
    private Account a;
    private ContentWorkspace cw;
    private ContentFolder cf;

    public ContentQueueable() {
    }
    
    public void execute(QueueableContext qc) {
        if (this.a == null) {
            this.a = new Account(Name = 'Test');
            insert this.a;
            System.enqueueJob(this); // chain to continue
        } else if (this.cw == null) {
            this.cw = new ContentWorkspace(Name = 'Test');
            insert this.cw;
            System.enqueueJob(this); // chain to continue
        } else if (this.cf == null) {
           // create Folder within that Library
            ContentFolder parentFolder = [select Id from ContentFolder where Name = :this.cw.Id];
            this.cf = new ContentFolder();
            this.cf.Name = 'Test';
            this.cf.ParentContentFolderId = parentFolder.Id;
            insert this.cf;
        }
    }
}

(This throws a different Content-related error which I'm not familiar with related to permissions on the created ContentWorkspace, but it does avoid the Mixed DML problem).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.