I’m sure a lot of you have this documented somewhere but I’ve recently discovered that it’s quite difficult to find an obvious reference to this knowledge on the interwobbles. So how would you create a Generic SObject at run-time? It’s rather easy thankfully:
String sObjectName = 'MyObject__c';
Schema.SObjectType t = Schema.getGlobalDescribe().get(sObjectName);
SObject s = t.newSObject();
If you require this type of functionality quite often I’d suggest putting it in a utility class.
Interesting post, Wes. What would be a possible use case for this? When you call Schema.getGlobalDescribe().get(SObjectName), what is returned since that object hasn’t been created yet?
~ Clint
Clint, I’ll be demonstrating that in my next post but it would assist you in fullfilling one of the core requirements of OOP, namely Polymorphism.
Gotcha. I was thinking you were referring to creating a new Object in the org (say via metadata). Looking forward to the next post, too.
Pity you are then dead in the water when you want to do a bulk upsert as AFAIK there is no way to instantiate the correctly typed list that is required starting from the object type name…
Because of the Upsert on generic SObject list limitation?
Yes; if you are creating many objects of one SObject type you want to insert a list of them rather than insert them one by one. And there is no support for something like:
List myList = List.newInstanceForType(‘Account’);
// Create multiple SObjects here
insert myList;
I might be misunderstanding, but I’ve done that there: http://th3silverlining.com/2011/01/28/salesforce-programmatically-populating-sample-data-post-deployment/
Or am I doing something a bit different?
Note: You cannot upsert SOBject lists, but you can insert.
No its me thats wrong as this test works:
@isTest
static void test() {
Contact c = new Contact(LastName =’abc’);
Account a = new Account(Name = ‘def’);
List l = new List{c, a};
insert l;
System.assertEquals(1, [select Count() from Contact where Name = ‘abc’]);
System.assertEquals(1, [select Count() from Account where Name = ‘def’]);
System.assertEquals(0, [select Count() from Contact where Name = ‘123’]);
System.assertEquals(0, [select Count() from Account where Name = ‘456’]);
c.LastName = ‘123’;
a.Name = ‘456’;
update l;
System.assertEquals(0, [select Count() from Contact where Name = ‘abc’]);
System.assertEquals(0, [select Count() from Account where Name = ‘def’]);
System.assertEquals(1, [select Count() from Contact where Name = ‘123’]);
System.assertEquals(1, [select Count() from Account where Name = ‘456’]);
try {
upsert l;
} catch (Exception e) {
System.assertEquals(‘DML on generic List only allowed for insert, update or delete’, e.getMessage());
}
}
Not sure where I picked up m wrong understanding of this. Thanks for taking the time to comment
When converting some code to use List<SObject> instead of e.g. List<Contact> for an insert I had to change the API version from 18.0 to 20.0 for it to work at runtime. So it appears the generic list support is a recent improvement in the API.
Sorry I meant to post that I’d had this issue too. Glad you figured it out.
Nice catch Wes, I am sure it was not noticed by many 🙂
When i try to update the sobject dynamically it throws me a error saying “System.SObjectException: Field Id is not editable”. Can you please help on this:
Schema.SObjectType t = Schema.getGlobalDescribe().get(‘Account’);
SObject sObjectAccount = t.newSObject();
sObjectAccount.put(‘Id’, ‘001G000000pyDGL’);
sObjectAccount.put(‘Name’, ‘Test’);
Update sObjectAccount;
interesting & very useful post.. 🙂