为何未查询Client_Contact__c字段却未触发SObject字段缺失错误?
问题原因与场景分析
为什么你的代码没触发错误?
核心原因很简单:Salesforce抛出的「SObject row was retrieved via SOQL without querying the requested field」错误,只在你尝试读取一个未通过SOQL查询获取的字段值时才会触发,而你只是对这个字段执行了赋值(写操作),并没有读取它的现有值。
举个例子,假设你的代码逻辑是这样的:
// 仅查询Account的Id Account targetAcc = [SELECT Id FROM Account WHERE Id = :Trigger.new[0].Id]; // 给未查询的字段赋值,写操作不会报错 targetAcc.Client_Contact__c = newContact.LastName; update targetAcc;
这段代码里,你只是把Contact的LastName赋值给Client_Contact__c,完全没有去读取这个字段原来的值——这种写操作不需要依赖SOQL查询返回的字段数据,所以不会触发错误。但如果加一行String oldValue = targetAcc.Client_Contact__c;来读取这个未查询的字段,立刻就会抛出那个错误。
该错误不会出现的场景
- 仅对SOQL查询的SObject做写操作:只要不读取未查询的字段,单纯赋值、执行DML更新都不会报错
- 操作触发器上下文变量:
Trigger.new、Trigger.old、Trigger.newMap这些上下文对象是Salesforce自动提供的完整记录快照,不管你有没有显式查询,都可以直接访问或修改字段(只要字段在当前触发器上下文里可用,比如after insert的Trigger.new包含插入后的所有字段值) - 访问SObject的Id字段:SOQL查询默认会自动返回Id字段,哪怕你没在SELECT语句里写
Id,直接访问acc.Id也永远不会触发错误 - 处理本地创建/刚完成DML的SObject实例:比如你刚执行
Account acc = new Account(Name='测试'); insert acc;,直接通过本地变量acc访问或修改字段,不需要SOQL查询,自然不会触发该错误 - 克隆SObject实例后赋值:用
acc.clone()创建新实例,对新实例的字段赋值,只要不读取原实例中未查询的字段,就不会报错 - 批量DML时指定更新字段:比如用
Database.update(accList, new List<String>{'Client_Contact__c'});明确指定要更新的字段,即使SOQL没查全字段,也不会触发错误
内容的提问来源于stack exchange,提问作者riseAJdev
相关产品推荐
相关产品推荐

