+ Start a Discussion
dmchengdmcheng 

Generic sobject, field not editable error on master-detail field

Hello. I'm doing some dynamic Apex and creating a generic SObject record using this method:

	//Create a generic sObject with a specified object type.
	//If the kns includes the target Id, include it because we'll be doing an update.
	private static sObject createObject(String typeName, String objId) {
		Schema.SObjectType targetType = Schema.getGlobalDescribe().get(typeName);
		SObject sobj = (objId != null) ? targetType.newSObject(objId) : targetType.newSObject();
		return sobj;
	}

 

The problem is, some of the objects I'm creating are on the child side of a master-detail relationship, and when I try to populate the relationship ID field in the sobject record, I get "Field is not editable" error.

	sobj.put('Contact__c', conId);

 

 

Is there any way around this?
 

Thanks
David

Best Answer chosen by Admin (Salesforce Developers) 
sfdcfoxsfdcfox

The workaround to this problem is rather convoluted. It'd be nice if the generic SObject class would look at Id before determining a "sometimes-editable" field's read-only status, but this simply isn't the case. The solution I have to work around such an annoying limitation is to leverage JSON parsing. Here's how that might work:

 

string s = json.serialize(sobj);
s = s.replaceFirst('\\}','},"Contact__c":"'+conId+'"');
sobj = (sobject)json.deserialize(s,sobject.class);

The only downside to this exact approach is that we're depending on "attributes" not being removed in a future release of JSON parsing, which would screw this up, but we could just as easily inject it into a known indice into the string.

 

We serialize to a string, inject our unwritable field, then deserialize back to an sobject. This even works on system fields, such as LastModifiedBy, but you must remember that this is only in-memory. This workaround won't allow you to modify a locked field, but the system validation will allow a master-detail field to be set when ID is null, so it will work as advertised.

All Answers

sfdcfoxsfdcfox

The workaround to this problem is rather convoluted. It'd be nice if the generic SObject class would look at Id before determining a "sometimes-editable" field's read-only status, but this simply isn't the case. The solution I have to work around such an annoying limitation is to leverage JSON parsing. Here's how that might work:

 

string s = json.serialize(sobj);
s = s.replaceFirst('\\}','},"Contact__c":"'+conId+'"');
sobj = (sobject)json.deserialize(s,sobject.class);

The only downside to this exact approach is that we're depending on "attributes" not being removed in a future release of JSON parsing, which would screw this up, but we could just as easily inject it into a known indice into the string.

 

We serialize to a string, inject our unwritable field, then deserialize back to an sobject. This even works on system fields, such as LastModifiedBy, but you must remember that this is only in-memory. This workaround won't allow you to modify a locked field, but the system validation will allow a master-detail field to be set when ID is null, so it will work as advertised.

This was selected as the best answer
dmchengdmcheng

Wow, thanks - I will give this a try.

dmchengdmcheng

I made an error in my design concept, so it turns out I don't have to use this after all:
 

1. When I instantiate the sobject in order to insert a new child object record, I can use the put method to place the contact ID into the Contact__c field.
 

2. When I instantiate the sobject in order to update an existing child object record, I can ignore the Contact__c field since I don't want to change the contact relationship. This was my mistake - I was trying to populate the field when there's no need to do so.
 

Thanks as always for your quick and clear responses, sfdcfox.