精通 Salesforce 标准对象:SOQL 与 DML 开发人员指南
背景与应用场景
作为一名 Salesforce 开发人员,我们的日常工作与数据模型紧密相连,而数据模型的核心便是对象(Objects)。在 Salesforce 平台中,对象分为两种:标准对象(Standard Objects)和自定义对象(Custom Objects)。标准对象是 Salesforce 预先构建好的对象,它们构成了 CRM(客户关系管理)功能的基础,例如客户(Account)、联系人(Contact)、业务机会(Opportunity)和个案(Case)。
这些标准对象不仅仅是简单的数据表,它们内置了复杂的业务逻辑、用户界面和自动化功能,是 Salesforce强大功能的基石。无论是构建一个复杂的业务流程自动化,还是开发一个自定义的 Lightning Web Component,我们都不可避免地需要与这些标准对象进行交互——查询数据、创建新记录、更新现有信息或删除不再需要的数据。
一个典型的应用场景是:当一个客户(Account)的行业(Industry)字段被更新为“金融”时,系统需要自动为该客户创建一个跟进任务(Task),并将其分配给客户的所有者。这个看似简单的需求,背后就需要开发人员使用 Apex 编程语言,通过 SOQL 查询相关的客户信息,再通过 DML 操作来创建新的任务记录。理解如何高效、安全地操作标准对象,是衡量一名 Salesforce 开发人员专业能力的重要标准。
原理说明
从开发人员的角度看,与标准对象交互主要通过两种核心的 Apex 语言特性:Salesforce Object Query Language (SOQL) 和 Data Manipulation Language (DML)。
Salesforce Object Query Language (SOQL)
SOQL 是一种专门用于查询 Salesforce 数据库中记录的语言。它的语法与标准的 SQL 非常相似,但更为精简,并且是为 Salesforce 的多租户(multi-tenant)架构量身定制的。通过 SOQL,我们可以精确地从一个或多个相关的对象中检索数据。
一个基本的 SOQL 查询结构如下:
SELECT [字段列表] FROM [对象名] WHERE [过滤条件] ORDER BY [排序字段] LIMIT [数量]
- SELECT: 指定需要查询的字段。最佳实践是只查询你需要的字段,而不是所有字段,以提高性能。 - FROM: 指定要查询的对象,例如
- WHERE: 设置过滤条件,缩小查询结果范围。这是优化查询性能、避免触及 Governor Limits 的关键。 - ORDER BY: 对查询结果进行排序。 - LIMIT: 限制返回的记录数量。
Account
或 Contact
。
SOQL 的强大之处在于其能够轻松处理对象之间的关系查询。例如,我们可以通过一个查询同时获取客户(Account)以及其下所有联系人(Contacts)的信息。
Data Manipulation Language (DML)
DML 是用于在数据库中插入、更新、删除和恢复记录的 Apex 语句。与 SOQL 不同,DML 不是一种查询语言,而是一组操作命令。
主要的 DML 语句包括:
- insert: 创建新记录。 - update: 更新现有记录。 - upsert: 更新现有记录,如果记录不存在则创建新记录(基于指定的外部 ID 字段或标准 Id 字段)。 - delete: 将记录移入回收站。 - undelete: 从回收站中恢复记录。 - merge: 合并最多三个同类型的记录。
在 Apex 中,DML 操作可以针对单个 sObject 记录,也可以针对一个 sObject 记录列表。为了遵循 Salesforce 的最佳实践并避免超出 Governor Limits,我们应始终对列表(List)进行 DML 操作,这被称为“批量化”(Bulkification)。
示例代码
以下示例代码均来自 Salesforce 官方开发者文档,展示了如何通过 Apex 使用 SOQL 和 DML 与标准对象进行交互。
示例 1:使用 SOQL 查询客户及其关联的联系人
这个例子展示了一个关系查询(relationship query),通过单个 SOQL 语句获取 Account 记录以及其所有子级的 Contact 记录。这在需要展示主从(master-detail)信息的场景中非常有用。
// SOQL query to retrieve account records and their related contacts // This is a common pattern for parent-to-child queries. // The subquery (SELECT Id, LastName FROM Contacts) fetches child records. List<Account> accts = [SELECT Id, Name, (SELECT Id, LastName FROM Contacts) FROM Account WHERE Name = 'SFDC Computing']; // The results are iterated over. The related contacts are accessed // via the relationship name, which is 'Contacts' in this case. for (Account a : accts) { System.debug('Account: ' + a.Name); List<Contact> cons = a.Contacts; for (Contact c : cons) { System.debug(' Contact: ' + c.LastName); } }
代码注释:
- 第 4 行: 执行 SOQL 查询。
(SELECT Id, LastName FROM Contacts)
是一个子查询,用于获取与每个 Account 关联的 Contact 记录。Contacts
是标准的子关系名称。
- 第 8-13 行: 遍历查询结果。
a.Contacts
让我们能够直接访问每个 Account 对象下关联的 Contact 记录列表,无需再次执行查询,这极大地提升了效率。
示例 2:创建和更新 Account 记录
这个例子演示了最基本的 DML 操作:insert
和 update
。它遵循了先在内存中创建对象实例,设置字段值,然后通过 DML 语句将其持久化到数据库的模式。
// Create a new Account sObject instance in memory. // Standard objects are instantiated just like custom objects. Account acct = new Account(Name='Global Media'); // The insert DML statement persists the new record to the database. // It's a best practice to wrap DML in a try-catch block for error handling. try { insert acct; // After the insert, the 'Id' field is populated by the system. System.debug('Account inserted with ID: ' + acct.Id); } catch (DmlException e) { System.debug('An unexpected error has occurred: ' + e.getMessage()); } // To update the record, modify the field values of the sObject variable. acct.Name = 'Global Media Inc.'; acct.BillingCity = 'San Francisco'; // The update DML statement commits the changes to the database. try { update acct; System.debug('Account updated successfully.'); } catch (DmlException e) { System.debug('An error occurred during update: ' + e.getMessage()); }
代码注释:
- 第 3 行: 在内存中创建一个新的
Account
对象实例,并设置Name
字段的值。
- 第 7 行: 使用
insert
语句将这个新对象保存到数据库。一旦插入成功,Salesforce 会自动为 acct.Id
字段赋值。
- 第 8-11 行: 使用 try-catch
块捕获可能发生的 DML 异常,例如必填字段缺失或校验规则失败。
- 第 14-15 行: 修改内存中 acct
对象的字段值,为接下来的更新操作做准备。
- 第 19 行: 使用 update
语句将这些更改提交到数据库。
注意事项
在操作标准对象时,开发人员必须时刻注意 Salesforce 平台的限制和特性,以确保代码的健壮性和可扩展性。
1. 权限与共享模型(Permissions & Sharing Model)
Apex 代码默认在系统模式(system mode)下运行,这意味着它会忽略对象权限(Object Permissions)和字段级安全(Field-Level Security, FLS)。但是,它仍然会遵守记录级的共享规则(Sharing Rules)。你可以使用 with sharing
或 without sharing
关键字在类定义中明确指定其共享行为。在处理敏感数据时,必须仔细考虑代码的运行上下文,确保不会意外地暴露或修改用户无权访问的数据。
2. Governor Limits
Salesforce 是一个多租户平台,为了保证所有用户共享资源的公平性,平台对代码执行施加了严格的资源限制,即 Governor Limits。与标准对象交互时,最常遇到的限制包括:
- SOQL 查询限制: 每个 Apex 事务(transaction)中,同步执行的 SOQL 查询总数不能超过 100 个。
- DML 语句限制: 每个事务中,DML 操作(insert, update 等)的调用次数不能超过 150 次。
- 记录处理限制: 单次 DML 操作处理的记录总数不能超过 10,000 条。
为了避免超出这些限制,必须采用批量化(Bulkification)的设计模式,即始终将 DML 和 SOQL 操作放在循环之外,并处理记录列表,而不是单个记录。
3. 错误处理
DML 操作可能会因为各种原因失败,如触发了验证规则、字段为空、记录被锁定等。简单的 DML 语句(如 insert myAccounts;
)是“要么全成功,要么全失败”的。如果列表中的任何一条记录导致错误,整个操作都会回滚。为了更精细地控制,应使用 Database
类的方法,例如 Database.insert(myAccounts, false)
。第二个参数设置为 false
允许部分成功,然后你可以遍历返回的 Database.SaveResult
列表来识别哪些记录成功了,哪些失败了,以及失败的原因。
总结与最佳实践
标准对象是 Salesforce 平台的核心,作为开发人员,我们的大部分工作都围绕着它们展开。熟练、高效地使用 SOQL 和 DML 与这些对象进行交互,是编写高质量 Salesforce 应用的基础。
以下是一些关键的最佳实践总结:
- 永远不要在循环中执行 SOQL 或 DML 操作:这是 Salesforce 开发的第一法则。这样做会迅速耗尽 Governor Limits。正确的做法是先收集所有需要处理的 ID 或数据,然后一次性执行查询或 DML 操作。
- 编写选择性的 SOQL 查询:在
WHERE
子句中使用索引字段(如 Id、Name、外部 ID、索引自定义字段)来过滤数据,并且只查询你真正需要的字段,避免使用SELECT Id, Name, ...
来查询所有字段,这能显著提升性能。 - 充分利用关系查询:通过子查询或父对象引用(如
Contact.Account.Name
)来减少 SOQL 查询的次数。一次查询获取主对象和关联对象的数据,远比多次单独查询高效。 - 始终考虑批量化:你的 Apex Trigger 或方法应该被设计为能够处理从一条到上万条记录的任何情况。使用 List、Set 和 Map 等集合类型来高效处理批量数据。
- 优雅地处理异常和错误:使用
try-catch
块来捕获 DML 异常,并考虑使用Database
类的方法进行部分成功操作,为用户提供清晰的错误反馈。
通过遵循这些原则,你不仅可以构建出功能强大的应用程序,还能确保它们在 Salesforce 复杂的多租户环境中稳定、高效地运行。对标准对象的深入理解和熟练运用,是每一位 Salesforce 开发人员通往卓越的必经之路。
评论
发表评论