salesforce-developer

salesforce-developer

热门

编写和调试Apex代码,构建Lightning Web组件,优化SOQL查询,实现触发器、批处理作业、平台事件以及Salesforce平台上的集成。适用于开发Salesforce应用程序、定制CRM工作流、管理调控器限制、批量处理或设置Salesforce DX和CI/CD流水线。

1.1万Star
974Fork
更新于 2026/5/20
SKILL.md
readonly只读
name
salesforce-developer
description

编写和调试Apex代码,构建Lightning Web组件,优化SOQL查询,实现触发器、批处理作业、平台事件以及Salesforce平台上的集成。适用于开发Salesforce应用程序、定制CRM工作流、管理调控器限制、批量处理或设置Salesforce DX和CI/CD流水线。

Salesforce开发者

核心工作流

  1. 分析需求 - 理解业务需求、数据模型、调控器限制、可扩展性
  2. 设计方案 - 选择声明式还是编程式,规划批量处理,设计集成
  3. 实现 - 按照最佳实践编写Apex类、LWC组件、SOQL查询
  4. 验证调控器限制 - 在继续之前,确保SOQL/DML计数、堆大小和CPU时间在平台限制内
  5. 全面测试 - 编写测试类,覆盖率90%以上,测试批量场景(200条记录批次)
  6. 部署 - 使用Salesforce DX、临时组织、CI/CD进行元数据部署

参考指南

根据上下文加载详细指导:

主题 参考 加载时机
Apex开发 references/apex-development.md 类、触发器、异步模式、批处理
Lightning Web组件 references/lightning-web-components.md LWC框架、组件设计、事件、wire服务
SOQL/SOSL references/soql-sosl.md 查询优化、关系、调控器限制
集成模式 references/integration-patterns.md REST/SOAP API、平台事件、外部服务
部署与DevOps references/deployment-devops.md Salesforce DX、CI/CD、临时组织、元数据API

约束

必须做

  • 批量化Apex代码 — 在循环前收集ID/记录,在循环外进行查询/DML
  • 编写测试类,代码覆盖率至少90%,包括批量场景
  • 使用带索引字段的选择性SOQL查询;利用关系查询
  • 对长时间运行的工作使用适当的异步处理(批处理、可排队、未来方法)
  • 实现适当的错误处理和日志记录;使用Database.update(scope, false)实现部分成功
  • 使用Salesforce DX进行源码驱动开发和元数据部署

禁止做

  • 在循环内执行SOQL/DML(违反调控器限制 — 见下面的批量触发器模式)
  • 在代码中硬编码ID或凭据
  • 创建没有保护措施的递归触发器
  • 跳过字段级安全性和共享规则检查
  • 使用已弃用的Salesforce API或组件

代码模式

批量触发器(正确模式)

// 正确:收集ID,在循环外只查询一次
trigger AccountTrigger on Account (before insert, before update) {
    AccountTriggerHandler.handleBeforeInsert(Trigger.new);
}

public class AccountTriggerHandler {
    public static void handleBeforeInsert(List<Account> newAccounts) {
        Set<Id> parentIds = new Set<Id>();
        for (Account acc : newAccounts) {
            if (acc.ParentId != null) parentIds.add(acc.ParentId);
        }
        Map<Id, Account> parentMap = new Map<Id, Account>(
            [SELECT Id, Name FROM Account WHERE Id IN :parentIds]
        );
        for (Account acc : newAccounts) {
            if (acc.ParentId != null && parentMap.containsKey(acc.ParentId)) {
                acc.Description = 'Child of: ' + parentMap.get(acc.ParentId).Name;
            }
        }
    }
}
// 错误:循环内SOQL — 违反调控器限制
trigger AccountTrigger on Account (before insert) {
    for (Account acc : Trigger.new) {
        Account parent = [SELECT Id, Name FROM Account WHERE Id = :acc.ParentId]; // 错误
        acc.Description = 'Child of: ' + parent.Name;
    }
}

批处理Apex

public class ContactBatchUpdate implements Database.Batchable<SObject> {
    public Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator([SELECT Id, Email FROM Contact WHERE Email = null]);
    }
    public void execute(Database.BatchableContext bc, List<Contact> scope) {
        for (Contact c : scope) {
            c.Email = 'unknown@example.com';
        }
        Database.update(scope, false); // 允许部分成功
    }
    public void finish(Database.BatchableContext bc) {
        // 发送通知或链接下一个批次
    }
}
// 执行:Database.executeBatch(new ContactBatchUpdate(), 200);

测试类

@IsTest
private class AccountTriggerHandlerTest {
    @TestSetup
    static void makeData() {
        Account parent = new Account(Name = 'Parent Co');
        insert parent;
        Account child = new Account(Name = 'Child Co', ParentId = parent.Id);
        insert child;
    }

    @IsTest
    static void testBulkInsert() {
        Account parent = [SELECT Id FROM Account WHERE Name = 'Parent Co' LIMIT 1];
        List<Account> children = new List<Account>();
        for (Integer i = 0; i < 200; i++) {
            children.add(new Account(Name = 'Child ' + i, ParentId = parent.Id));
        }
        Test.startTest();
        insert children;
        Test.stopTest();

        List<Account> updated = [SELECT Description FROM Account WHERE ParentId = :parent.Id];
        System.assert(!updated.isEmpty(), '子记录应有描述');
        System.assert(updated[0].Description.startsWith('Child of:'), '描述格式不匹配');
    }
}

SOQL最佳实践

// 选择性查询 — 在WHERE子句中使用索引字段
List<Opportunity> opps = [
    SELECT Id, Name, Amount, StageName
    FROM Opportunity
    WHERE AccountId IN :accountIds      // 索引字段
      AND CloseDate >= :Date.today()    // 索引字段
    ORDER BY CloseDate ASC
    LIMIT 200
];

// 关系查询以避免额外的往返
List<Account> accounts = [
    SELECT Id, Name,
           (SELECT Id, LastName, Email FROM Contacts WHERE Email != null)
    FROM Account
    WHERE Id IN :accountIds
];

Lightning Web组件(计数器示例)

<!-- counterComponent.html -->
<template>
    <lightning-card title="计数器">
        <div class="slds-p-around_medium">
            <p>计数:{count}</p>
            <lightning-button label="增加" onclick={handleIncrement}></lightning-button>
        </div>
    </lightning-card>
</template>
// counterComponent.js
import { LightningElement, track } from 'lwc';
export default class CounterComponent extends LightningElement {
    @track count = 0;
    handleIncrement() {
        this.count += 1;
    }
}
<!-- counterComponent.js-meta.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>59.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
    </targets>
</LightningComponentBundle>

文档