You need to sign in to do that
Don't have an account?
Tim May 12
Mixed DML Error Auth.ConfigurableSelfRegHandler Issue
Hello,
I have implemented a Configurable Self Registration Handler in a Community and used the Auth.ConfigurableSelfRegHandler to extend how the User / Contact is created.
I want the Contact that is made to have a particular RecordType. I updated the method generateContact() to either look for a Contact or create a new Contact. I started with the example code that is created when you enable a handler in the Community.
Here is the error I am getting:
Update failed. First exception on row 0 with id <ID>; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): User, original object: Contact: []
I know the User object is a setup object but I figured Site.createExternalUser() would be able to bypass that.
Thanks for the assistance, code is below.
I have implemented a Configurable Self Registration Handler in a Community and used the Auth.ConfigurableSelfRegHandler to extend how the User / Contact is created.
I want the Contact that is made to have a particular RecordType. I updated the method generateContact() to either look for a Contact or create a new Contact. I started with the example code that is created when you enable a handler in the Community.
Here is the error I am getting:
Update failed. First exception on row 0 with id <ID>; first error: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa): User, original object: Contact: []
I know the User object is a setup object but I figured Site.createExternalUser() would be able to bypass that.
Thanks for the assistance, code is below.
global class AutocreatedConfigSelfReg implements Auth.ConfigurableSelfRegHandler { private final Long CURRENT_TIME = Datetime.now().getTime(); private final String[] UPPERCASE_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); private final String[] LOWERCASE_CHARS = 'abcdefghijklmnopqrstuvwxyz'.split(''); private final String[] NUMBER_CHARS = '1234567890'.split(''); private final String[] SPECIAL_CHARS = '!#$%-_=+<>'.split(''); // This method is called once after verification (if any was configured). // This method should create a user and insert it. // Password can be null. // Return null or throw an exception to fail creation. global Id createUser(Id accountId, Id profileId, Map<SObjectField, String> registrationAttributes, String password) { User u = new User(); u.ProfileId = profileId; for (SObjectField field : registrationAttributes.keySet()) { String value = registrationAttributes.get(field); u.put(field, value); } u = handleUnsetRequiredFields(u); Contact cnct = generateContact(u, accountId); if (cnct.Id != null) { u.ContactId = cnct.Id; } if (String.isBlank(password)) { password = generateRandomPassword(); } Site.validatePassword(u, password, password); if (u.contactId == null) { return Site.createExternalUser(u, accountId, password, True); } u.languagelocalekey = UserInfo.getLocale(); u.localesidkey = UserInfo.getLocale(); u.emailEncodingKey = 'UTF-8'; u.timeZoneSidKey = UserInfo.getTimezone().getID(); insert u; System.setPassword(u.Id, password); return u.id; } // Method to autogenerate a password if one isn't passed in. // By setting a password for a user, we won't send a // welcome email to set the password. private String generateRandomPassword() { String[] characters = new List<String>(UPPERCASE_CHARS); characters.addAll(LOWERCASE_CHARS); characters.addAll(NUMBER_CHARS); characters.addAll(SPECIAL_CHARS); String newPassword = ''; Boolean needsUpper = true, needsLower = true, needsNumber = true, needsSpecial = true; while (newPassword.length() < 50) { Integer randomInt = generateRandomInt(characters.size()); String c = characters[randomInt]; if (needsUpper && c.isAllUpperCase()) { needsUpper = false; } else if (needsLower && c.isAllLowerCase()) { needsLower = false; } else if (needsNumber && c.isNumeric()) { needsNumber = false; } else if (needsSpecial && !c.isAlphanumeric()) { needsSpecial = false; } newPassword += c; } newPassword = addMissingPasswordRequirements(newPassword, needsLower, needsUpper, needsNumber, needsSpecial); return newPassword; } private String addMissingPasswordRequirements(String password, Boolean addLowerCase, Boolean addUpperCase, Boolean addNumber, Boolean addSpecial) { if (addLowerCase) { password += LOWERCASE_CHARS[generateRandomInt(LOWERCASE_CHARS.size())]; } if (addUpperCase) { password += UPPERCASE_CHARS[generateRandomInt(UPPERCASE_CHARS.size())]; } if (addNumber) { password += NUMBER_CHARS[generateRandomInt(NUMBER_CHARS.size())]; } if (addSpecial) { password += SPECIAL_CHARS[generateRandomInt(SPECIAL_CHARS.size())]; } return password; } // Generates a random number from 0 up to, but not including, max. private Integer generateRandomInt(Integer max) { return Math.mod(Math.abs(Crypto.getRandomInteger()), max); } // Loops over required fields that were not passed in to // set to some default value. private User handleUnsetRequiredFields(User u) { if (String.isBlank(u.LastName)){ u.LastName = generateLastName(); } if (String.isBlank(u.Username)) { u.Username = generateUsername(); } if (String.isBlank(u.Email)) { u.Email = generateEmail(); } if (String.isBlank(u.Alias)) { u.Alias = generateAlias(); } if (String.isBlank(u.CommunityNickname)) { u.CommunityNickname = generateCommunityNickname(); } return u; } // Method to construct a contact for a user. private void generateContact(User u, Id accountId) { Contact cntct; // Contacts from the Community will have an additional contact record type List<RecordType> contactRecordTypes = [SELECT Id FROM RecordType WHERE SObjectType = 'Contact' and DeveloperName = 'Community_Contact']; // First step, look to see if there is a Contact already List<Contact> contactCheck = [SELECT Id, FirstName, LastName, AccountId FROM Contact WHERE Email = :u.Email]; // There is one and only one Contact that we found, so return it. if (contactCheck.isEmpty() == false && contactCheck.size() == 1) { System.debug('Found an existing Contact based on Email Address'); // Update the contact record with the information from the registration form // but make sure to not adjust the Account Id for security reasons. cntct = contactCheck.get(0); cntct.RecordTypeId = contactRecordTypes.get(0).Id; cntct.Active_Contact__c = true; cntct.LeadSource = 'Salesforce Community'; cntct.FirstName = u.FirstName; cntct.LastName = u.LastName; update cntct; } else { // There was no Contact record found, so we need to make one // and put it in the right location. System.debug('Creating a new Contact'); cntct.RecordTypeId = contactRecordTypes.get(0).Id; cntct.AccountId = accountId; cntct.Active_Contact__c = true; cntct.LeadSource = 'Salesforce Community'; cntct.FirstName = u.FirstName; cntct.LastName = u.LastName; cntct.Email = u.Email; insert cntct; } System.debug('cntct: ' + cntct); return cntct; } // Default implementation to try to provide uniqueness. private String generateAlias() { String timeString = String.valueOf(CURRENT_TIME); return timeString.substring(timeString.length() - 8); } // Default implementation to try to provide uniqueness. private String generateLastName() { return 'ExternalUser' + CURRENT_TIME; } // Default implementation to try to provide uniqueness. private String generateUsername() { return 'externaluser' + CURRENT_TIME + '@company.com'; } // Default implementation to try to provide uniqueness. private String generateEmail() { return 'externaluser' + CURRENT_TIME + '@company.com'; } // Default implementation to try to provide uniqueness. private String generateCommunityNickname() { return 'ExternalUser' + CURRENT_TIME; } }
Did you find any solution for this issue.
Thanks