Salesforce 开发人员指南:深入解析自定义对象 (Custom Objects)

背景与应用场景

作为一名 Salesforce 开发人员,我们日常工作的核心就是围绕数据展开。Salesforce 平台提供了一系列功能强大的标准对象 (Standard Objects),如 Account (客户)、Contact (联系人) 和 Opportunity (商机),它们构成了 CRM 功能的基石。然而,任何一个复杂的业务系统都不可能仅靠标准对象来满足所有需求。这时,自定义对象 (Custom Objects) 就成了我们手中最强大的工具之一。

自定义对象本质上是您在 Salesforce 中创建的自定义数据库表,用于存储对您的组织或行业而言独一无二的信息。标准对象解决了“谁是我的客户”以及“我向他们销售什么”等通用问题,而自定义对象则可以回答更加具体、更具业务特色的问题。

应用场景举例:

  • 教育行业:一所大学可以使用名为 Course__c 的自定义对象来管理课程信息,使用 Enrollment__c 对象来追踪学生的选课记录。
  • 房地产行业:一家房地产公司可以创建 Property__c 对象来存储房产列表的详细信息,包括地址、价格、面积和照片等。
  • 项目管理:任何公司都可以创建 Project__cTask__c 对象来管理内部项目、分配任务并跟踪进度。
  • IT 服务管理:IT 部门可以创建 IT_Asset__c 对象来追踪公司所有的硬件和软件资产,记录其分配、维护和生命周期。

对于开发人员来说,自定义对象不仅仅是数据的容器。它们是 Apex 代码、Visualforce 页面、Lightning Web Components (LWC) 以及各种自动化流程(如 Flow 和 Apex Triggers)交互的核心。理解其底层结构、API 命名规则以及编程交互方式,是构建健壮、可扩展的 Salesforce 应用的前提。


原理说明

从开发人员的角度看,理解自定义对象的原理意味着要超越 UI 上的点击操作,深入其 API 层面和编程模型。以下是几个核心概念:

1. API 名称 (API Name)

这是自定义对象和自定义字段在代码中唯一的标识符。当您在 Salesforce UI 中创建一个自定义对象或字段时,系统会自动为其生成一个 API 名称。所有自定义对象和字段的 API 名称都以后缀 `__c` 结尾(`c` 代表 custom)。例如,如果您创建了一个标签为 "Project" 的自定义对象,其 API 名称可能是 Project__c。同样,在该对象上创建一个标签为 "Project Budget" 的字段,其 API 名称可能是 Project_Budget__c

关键点:在 Apex、SOQL、SOAP/REST API 调用以及 LWC/Aura 组件中,您必须使用 API 名称,而不是其显示标签 (Label)。这是初级开发者最容易犯的错误之一。

2. 数据类型与字段 (Data Types and Fields)

每个自定义对象都由一系列字段组成,就像数据库表的列一样。除了系统默认创建的标准字段(如 Id, Name, CreatedDate, OwnerId 等),我们可以添加各种类型的自定义字段,例如 Text, Number, Date, Checkbox, Picklist 等。作为开发者,我们需要精确地了解每个字段的 API 名称和数据类型,以便在代码中正确地查询和操作它们。

3. 关系 (Relationships)

关系是 Salesforce 数据模型的精髓。自定义对象可以通过关系字段与其他对象(标准或自定义)连接起来。

  • 查找关系 (Lookup Relationship): 一种相对松散的一对多关系。例如,一个 Task__c 对象可以通过一个 Lookup 字段关联到一个 Project__c 对象。在编程中,这表现为一个 ID 字段(如 Project__c)和一个关系名称(通常是 Project__r),我们可以通过这个关系名称在 SOQL 查询中直接获取父对象的字段。
  • 主从关系 (Master-Detail Relationship): 一种更紧密的一对多关系。子记录(Detail)的属主和共享权限由父记录(Master)控制。如果父记录被删除,所有子记录也会被级联删除。这种关系对于创建具有紧密业务逻辑的父子结构至关重要。编程访问方式与 Lookup 类似。

在 SOQL 中,我们可以使用 `__r` 后缀来遍历这些关系,从子对象查询父对象的字段(如 SELECT Project__r.Name FROM Task__c),或者使用子查询从父对象查询其所有子记录。

4. 编程访问:SOQL 和 DML

作为开发者,我们与自定义对象最主要的交互方式是通过代码:

  • SOQL (Salesforce Object Query Language): 用于从数据库中查询记录。我们可以像查询标准对象一样查询自定义对象,只需使用其 `__c` API 名称。
  • DML (Data Manipulation Language): 用于在数据库中插入、更新、删除或恢复记录。Apex 提供了 insert, update, delete, upsert 等 DML 语句来操作 sObject 记录列表。

这些操作构成了我们 Apex 业务逻辑的基础,无论是触发器、批处理类还是 LWC 的 Apex 控制器,都离不开对自定义对象的 SOQL 查询和 DML 操作。


示例代码

为了更好地说明如何在 Apex 中与自定义对象交互,我们假设已经创建了一个名为 Book__c 的自定义对象,它包含以下自定义字段:

  • Title__c (Text)
  • Author__c (Text)
  • Published_Year__c (Number)
  • Price__c (Currency)

下面的 Apex 代码段演示了如何创建、查询和更新 Book__c 记录。这些示例严格遵循 Salesforce 官方文档中的 DML 和 SOQL 语法。

// 开发者控制台或任何 Apex 类中执行
// ** 1. 创建并插入一条新的自定义对象记录 **

// 实例化一个新的 Book__c 对象,这在内存中创建了一个 sObject 变量
Book__c newBook = new Book__c();

// 为自定义字段赋值。注意,我们使用的是 API 名称(__c 后缀)
newBook.Title__c = 'The Apex Developer Guide';
newBook.Author__c = 'Salesforce Docs';
newBook.Published_Year__c = 2023;
newBook.Price__c = 59.99;

try {
    // 使用 DML 语句 'insert' 将内存中的 sObject 记录持久化到数据库
    insert newBook;
    
    // 插入成功后,记录的 Id 字段会被自动填充
    // 我们可以通过 System.debug 打印出来进行验证
    System.debug('新书创建成功,记录 ID 为: ' + newBook.Id);

} catch (DmlException e) {
    // 捕获可能发生的 DML 异常,例如触发了验证规则或必填字段为空
    System.debug('创建书籍记录时发生错误: ' + e.getMessage());
}

// ** 2. 使用 SOQL 查询刚刚创建的记录 **

// 确保 newBook.Id 不为空,以防上面的插入操作失败
if (newBook.Id != null) {
    // 使用 SOQL 查询来从 Book__c 对象中检索记录
    // WHERE 子句用于过滤,我们通过唯一的 Id 来精确查找
    Book__c queriedBook = [SELECT Id, Title__c, Author__c, Price__c FROM Book__c WHERE Id = :newBook.Id LIMIT 1];
    
    // 在调试日志中打印查询结果
    System.debug('查询到的书籍标题: ' + queriedBook.Title__c);
    System.debug('作者: ' + queriedBook.Author__c);

    // ** 3. 更新查询到的记录 **

    // 修改记录的字段值
    queriedBook.Price__c = 49.99; // 价格下调

    try {
        // 使用 DML 语句 'update' 将修改后的记录保存回数据库
        update queriedBook;
        System.debug('书籍价格更新成功!');
    
    } catch (DmlException e) {
        System.debug('更新书籍记录时发生错误: ' + e.getMessage());
    }
}

注意事项

在开发过程中使用自定义对象时,必须牢记以下几点,以避免性能问题、安全漏洞和违反平台限制。

1. 权限与安全性 (Permissions & Security)

用户的简档 (Profile) 或权限集 (Permission Set) 必须拥有对该自定义对象的相应访问权限(创建、读取、更新、删除 - CRUD)。此外,还需要考虑字段级安全 (Field-Level Security - FLS),确保用户只能访问他们被授权查看或编辑的字段。在 Apex 中,可以使用 WITH SECURITY_ENFORCED 子句进行 SOQL 查询,或使用 Security.stripInaccessible 方法来强制执行 FLS。

2. API 限制 (API Limits)

Salesforce 是一个多租户环境,为了保证平台稳定性,它对每个事务 (transaction) 中的操作都设有严格的执行限制 (Governor Limits)。与自定义对象交互时,最需要关注的是:

  • SOQL 查询限制:在单个同步事务中,最多只能执行 100 条 SOQL 查询。
  • DML 语句限制:在单个同步事务中,最多只能执行 150 次 DML 操作。
  • 查询返回行数限制:SOQL 查询总共不能返回超过 50,000 条记录。

这意味着绝对不能在循环(for, while)中执行 SOQL 查询或 DML 语句,否则会迅速耗尽限制,导致程序崩溃。这也就是我们常说的“代码批量化 (Bulkification)”的重要性。

3. 命名约定与描述 (Naming Conventions & Descriptions)

虽然系统对 API 名称的格式有要求,但良好的命名约定能极大地提高代码的可读性和可维护性。建议使用清晰、一致的命名方式(如 Project_Task__c 而不是 PT__c)。同样重要的是,在创建对象和字段时,务必填写描述 (Description)。这对于未来的你或其他接手项目的开发者来说,是理解数据模型意图的宝贵信息。

4. 错误处理 (Error Handling)

任何 DML 操作都可能失败,原因包括验证规则失败、触发器异常、缺少必要字段等。始终使用 try-catch 块来包裹 DML 语句,优雅地处理 DmlException。对于需要部分成功的场景(例如,插入100条记录,允许其中几条失败而不回滚整个事务),应该使用 Database 类的方法,如 Database.insert(records, false),并检查返回的 SaveResult 对象来处理成功和失败的记录。


总结与最佳实践

自定义对象是 Salesforce 平台灵活性的核心,也是我们开发者构建定制化解决方案的基石。它们将抽象的业务需求转化为具体、可操作的数据结构。对于开发人员而言,要高效、安全地使用自定义对象,应遵循以下最佳实践:

  1. 声明式优先 (Declarative First): 在编写 Apex 代码之前,首先思考是否能通过 Flow、验证规则或公式字段等声明式工具来满足需求。代码虽然强大,但维护成本更高。
  2. 坚持批量化 (Always Bulkify): 这是 Salesforce 开发的第一法则。确保你的代码(尤其是触发器)能够高效处理单条记录和批量记录(如通过 Data Loader 导入200条记录)。永远不要在循环中放置 DML 或 SOQL。
  3. 善用关系查询: 尽可能使用 SOQL 的关系查询(`__r`)和子查询来一次性获取相关数据,避免多次查询数据库,从而节省 SOQL 查询限额。
  4. 考虑数据倾斜 (Data Skew): 在设计数据模型时,要预见未来可能出现的数据量。避免设计出单个父记录下拥有超过 10,000 个子记录的结构,这可能导致记录锁定和性能问题。
  5. 代码即文档: 除了清晰的命名和详尽的描述外,你的代码本身也应具备良好的可读性。通过有意义的变量名和适当的注释,让其他开发者能够轻松理解你的逻辑。

总而言之,精通自定义对象的声明式配置和编程性使用,是衡量一个 Salesforce 开发人员能力的重要标尺。它不仅关乎技术实现,更体现了你对数据建模、平台限制和长远系统架构的深刻理解。

评论

此博客中的热门博文

Salesforce Einstein AI 编程实践:开发者视角下的智能预测

Salesforce 登录取证:深入解析用户访问监控与安全

Salesforce Experience Cloud 技术深度解析:构建社区站点 (Community Sites)