Salesforce Apex开发笔记

获取记录类型

Id rid = [select Id from RecordType where DeveloperName = 'Campaign' and sobjecttype ='DocumentCompiling__c'][0].Id;
RecordType recoType =  [select Id from RecordType where SobjectType = 'DocumentCompiling' and DeveloperName = 'BidDocumentation' limit 1];
Id recordTypeId = Schema.SObjectType.对象API.getRecordTypeInfosByName().get('记录类型名').getRecordTypeId();

备注:不建议用ByName查询记录类型,因为记录类型的Name会根据系统语言进行变更。

Id recordTypeId = Schema.SObjectType.对象名.getRecordTypeInfosByDeveloperName().get('记录类型名称').getRecordTypeId();

根据ID获取记录类型名

Schema.getGlobalDescribe().get(objectName).getDescribe().getRecordTypeInfosById().get(strRecordTypeId).getName();

锁定记录

先开启配置
Salesforce Apex开发笔记_第1张图片
例子

List<Order_Details__c> orddList = [Select Id,OrderNo__r.Status, OrderNo__c fromOrder_Details__cwhere OrderNo__c in : ordId];
//将数据锁定 可以是对象的List集合,也可以是Id的Set
Approval.LockResult[] lrList = Approval.lock(orddList, false);
//将数据解锁
Approval.UnlockResult[] lrList = Approval.unlock(orddList, false);

判断记录是否锁定:

Approval.isLocked(记录Id);

获取旧对象

trigger.oldMap.get();

Apex Scheduler类启动方法

Apex Scheduler类启动方法

proschedule p = new proschedule();
String sch = '0 0 8 13 2 ?';//秒分时日月周年
system.schedule('One Time Pro', sch, p);

每小时运行一次

System.schedule('交际费预算每小时运行一次', '0 0 * * * ?', new Sch_Interface_B2B_ComBudget() );

Salesforce Apex开发笔记_第2张图片
Salesforce Apex开发笔记_第3张图片
Salesforce Apex开发笔记_第4张图片

Apex batch调用方法

无参数情况并立即启动:

Database.executeBatch(new UpdateAccountFields());

Database.executeBatch(new UpdateAccountFields(),'ID',数量);

在apex类中给页面给 页面提示

原始页面报错:

对象.addError('');

自己定义的页面报错

ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR, '责任人字段必填'));

Salesforce Apex开发笔记_第5张图片

获取选项列表的值

List<String> listHaveAcquiredLsit = new List<String>();
        List<String> designInformationList = new List<String>();
        Integer i = 0;
        Schema.DescribeSObjectResult dsr = 对象名.sObjectType.getDescribe();
        Map<String, Schema.SObjectField> field_map = dsr.fields.getMap();
        List<Schema.PicklistEntry> HaveAcquiredValues = field_map.get('字段名').getDescribe().getPickListValues();
        List<Schema.PicklistEntry> DesignInfoValues = field_map.get('字段名').getDescribe().getPickListValues();
        for (Schema.PicklistEntry a : HaveAcquiredValues) {
            listHaveAcquiredLsit.add(a.getValue());
        }
        for (Schema.PicklistEntry a : DesignInfoValues) {
            designInformationList.add(a.getValue());
        }
public static Map<String,String> getPickList(String objectName,String fieldname){
        Map<String,String> picklistMap = new Map<String,String>();
        Schema.SObjectType targetType = Schema.getGlobalDescribe().get(objectName);//From the Object Api name retrieving the SObject
        Sobject Object_name = targetType.newSObject();
        Schema.sObjectType sobject_type = Object_name.getSObjectType(); //grab the sobject that was passed
        Schema.DescribeSObjectResult sobject_describe = sobject_type.getDescribe(); //describe the sobject
        Map<String, Schema.SObjectField> field_map = sobject_describe.fields.getMap(); //get a map of fields for the passed sobject
        List<Schema.PicklistEntry> pick_list_values = field_map.get(fieldname).getDescribe().getPickListValues(); //grab the list of picklist values for the passed field on the sobject
        for (Schema.PicklistEntry a : pick_list_values) { //for all values in the picklist list
          picklistMap.put(a.getValue(), a.getLabel());
       }
       return picklistMap;
    }

字符串

去空行

opp.Field4YZSQ__c = opp.Field4YZSQ__c.replaceAll('((\r\n)|\n)[\\s\t ]*(\\1)+', '$1').replaceAll('^((\r\n)|\n)', '');

替换

opp.Field4YZSQ__c = opp.Field4YZSQ__c.replaceAll(旧值,新值);

包含

contains

类型之间的转换

list转string

String s = String.join(集合名称,';')

string转list

str.split(';')

map转obj

Map<String,String> mapstr  = new Map<String,String>();
mapstr.put('Name', 'true');
mapstr.put('Id', 'eee');
String s = JSON.serialize(mapstr);
Account acc = (Account)JSON.deserialize(s, Account.class);
System.debug(acc);

Object 转 Map

 Map<String, Object> tempMap = (Map<String, Object>)JSON.deserializeUntyped(JSON.serialize(Object)); 

审批

SF中,与审批有关的对象:
ProcessInstance
关联了记录
ProcessInstanceHistory
PorcessInstanceHistory
被分配人 =======> OriginalActorId
实际批准人 =======> ActorId
审批日期 =======> SystemModstamp
审批状态 =======> StepStatus
审批整体状态 =======> 与之相对应的ProcessInstance上的Status
审批留言 =======> Comments
审批目标对象 =======> TargetObjectId
Approval Status:(ProcessInstance:Status, ProcessInstanceHistory:StepStatus)
中文名 API Name Label
已批准 =====>Approved =====> Approved
故障 =====>Fault =====> Fault
暂停 =====>Held =====> Hold
无响应 =====>NoResponse =====> NoResponse
待处理 =====>Pending => Pending
已重新分配
=>Reassigned =====> Reassigned
已拒绝 =====>Rejected =====> Rejected
已调回 =====>Removed =====> Recalled
已提交 =====>Started =====> Submitted
ProcessInstanceStep 已完成的审批
ProcessInstanceWorkitem 等待审批的记录
ProcessNode
TargetObject.

通过/拒绝某个节点的审批

//Class used for Approving Record
 Approval.ProcessWorkitemRequest req = new Approval.ProcessWorkitemRequest();
 req.setComments('Approving request for Opportunity');
 
 //Approve or Reject Record
 req.setAction('Approve');//设置状态为批注还是拒绝 Reject
 
 //Getting Work Item Id
 ProcessInstanceWorkitem pItem = [Select Id from ProcessInstanceWorkitem 
 where ProcessInstance.TargetObjectId =: opp.id];

 req.setWorkitemId(pItem.Id);
 // Submit the request for approval
 Approval.ProcessResult result = Approval.process(req);

自动提起审批流
单个提交审批

 Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
    req1.setComments('新供应商注册信息已提交,请审核!');
    req1.setObjectId(需要审批的记录的Id);
    req1.setSubmitterId(初始提交人Id);
    req1.setProcessDefinitionNameOrId('批准进程api Name');
   // req1.setNextApproverIds(approverIdList);// 下一步审批人,传入参数必须为List,注意是队列类型小组Id,而不是用户Id 
   // req1.setSkipEntryCriteria(true);// 是否跳过标准
    Approval.ProcessResult result = Approval.process(req1);

批量提交审批

List<Approval.ProcessSubmitRequest> requests = new List<Approval.ProcessSubmitRequest>();
	For(对象){
		Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
	        req1.setComments('新供应商注册信息已提交,请审核!');
	        req1.setObjectId(需要审批的记录的Id);
	        req1.setSubmitterId(初始提交人Id);
	        req1.setProcessDefinitionNameOrId('批准进程api Name');
	       // req1.setNextApproverIds(approverIdList);// 下一步审批人,传入参数必须为List,注意是队列类型小组Id,而不是用户Id 
	       // req1.setSkipEntryCriteria(true);// 是否跳过标准
		requests.add(req1); 
		
	}
	 Approval.ProcessResult[] processResults = Approval.process(requests);

加密/转码

https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_crypto.htm?search_text=Crypto
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_restful_encodingUtil.htm?search_text=EncodingUtil

Blob str = '';//要加密的数据

MD5加密

String myString = 'Some String';
Blob myBlob = Blob.valueOf(myString);
Blob md5hash = Crypto.generateDigest('MD5',myBlob);
System.debug(EncodingUtil.convertToHex(md5hash));//显示密文

Basic64转码

String uspastr = EncodingUtil.base64Encode(str );

获取自定义设置的内容

String defaultUser =  自定义对象APi.getInstance('BidPrincipal').字段;

获取集合

Map(String,obj) = 自定义对象APi.getall();
List = 自定义对象APi.getall().values();

来自 https://developer.salesforce.com/forums/?id=906F0000000MNvmIAG

获取字段的标签、API、选项列表的值

获取所有字段

SObjectType esalesTemp = Schema.getGlobalDescribe().get('表名称');
Map<String,Schema.SObjectField> mfields = esalesTemp.getDescribe().fields.getMap();

for (String s: mfields.keySet()) {
    SObjectField fieldToken = mfields.get(s);
          DescribeFieldResult selectedField = fieldToken.getDescribe();
          System.debug('===Name=='+selectedField.getName()); //API名称
          System.debug('===Label=='+selectedField.getLabel());  //字段标签
          System.debug('===Type=='+selectedField.getType());//数据类型
          Boolean isRequired = false;
          if (selectedField.isNillable() == false) {
            isRequired = true;
          }else{
            isRequired = false;
          }
          System.debug('===isRequired=='+isRequired);
}

获取特定的选项列表字段:

    List<String> result = new List<String>();
        Schema.DescribeFieldResult fieldResult = 表名称.字段API.getDescribe();
        List<Schema.PicklistEntry> ple = fieldResult.getPicklistValues();
        for( Schema.PicklistEntry f : ple)
        {
            result.add(f.getLabel());
        }       

表名称.字段API.getDescribe().getLabel()

// 获取全部字段

List fields = new List(AgreementPayment__c.SObjectType.getDescribe().fields.getMap().keySet());
Set  set_agmeId = new Set();
set_agmeId.addAll(map_agid_queidset.keySet());
String appaSql = 'select ' + String.join(fields, ',') + ' from AgreementPayment__c where Agreement__c in: set_agmeId';

获取Map集合的第一个值

Map<Decimal,Decimal> maps = new Map<Decimal,Decimal>();
maps.put(1, 2);
maps.put(2, 7);
maps.put(5, 9);
System.debug(maps.keySet().iterator().next());
System.debug(maps.values().iterator().next());

获取salesforce的链接

基础链接:

Url.getSalesforceBaseUrl().toExternalForm()

完全链接:

ApexPages.currentPage().getURL()

获取当前登录用户的id

UserInfo.getId();

通过Id获取对象

某个ID.getsobjecttype().getDescribe()
Id.valueOf('a0G0p0000005bVT').getsobjecttype().getDescribe().getName()

后台发送邮件

无邮件模板

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddresses = new String[] {UserInfo.getUserEmail()};
mail.setToAddresses(toAddresses);        
mail.setSenderDisplayName('销售目标');
mail.setSubject('主题');
mail.setHtmlBody( '内容' );
Messaging.sendEmail(new Messaging.SingleEmailMessage[] {mail});

有邮件模板

List<Messaging.SingleEmailMessage> emails  = new List<Messaging.SingleEmailMessage>();
Messaging.SingleEmailMessage temail = new Messaging.SingleEmailMessage();
temail.setSenderDisplayName('主题');
temail.setWhatId(邮件需要的对象Id);
temail.setTargetObjectId(联系人Id);
temail.setTreatTargetObjectAsRecipient(false);
temail.setTemplateId(邮件模板Id);
temail.setSaveAsActivity(false);
temail.setToAddresses(addresses);
emails.add(temail);
Messaging.sendEmail(emails);

如果需要的对象为潜客 则

temail.setWhatId(邮件需要的对象Id); 不需要了
temail.setTargetObjectId(联系人Id);修改为 temail.setTargetObjectId(潜客ID);

通过url下载附件保存到salesforce

// Instantiate a new http object
Http h = new Http();
// Instantiate a new HTTP request, specify the method (GET) as well as the endpoint
HttpRequest req = new HttpRequest();
req.setEndpoint('YOUR_URL');
req.setTimeout(60000);//sets maximum timeout
req.setMethod('GET');
// Send the request, and return a response
HttpResponse res = h.send(req);
Blob body = res.getBodyAsBlob();
//then you can attach this body wherever you want
Attachment att = new Attachment(Name = 'SET A NAME', Body = body, ContentType = 'SET A VALID CONTENT TYPE', ParentId='PARENT_OBJ_ID');
insert att;

来自 https://developer.salesforce.com/forums/?id=906F0000000ApEAIA0

文件下载

public class ImportOrderItemController
{
    public class PrboObj
    {
        public Boolean isCheck {get; set; }
        public Pricebook2 prbo {get; set; }
    }
    public Blob csvFileBody {get; set; } //csv文件内容
    public string csvAsString {get; set; }
    public String[] csvFileLines {get; set; } //存储csv中每行数据
    public String downurl {get; set; }
    public String orderId; //订单Id
    public class OritList
    {
        public String productCode {get; set; } //产品代码
        public String productname {get; set; } //产品名称
        public String callGues {get; set; }
        public OrderItem orit {get; set; }
    }
    public List < OritList > orderItemList {get; set; } //订单明细
    public List < PrboObj > prboList {get; set; }
    public String prboID = '';
    public String currencyIsoCode = '';
    public ImportOrderItemController()
    {
        prboList = new List < PrboObj > ();
        csvFileLines = new String[]
        {};
        orderItemList = New List < OritList > ();
        orderId = system.currentPageReference().getParameters().get('id');
        Order ord = [select Id, Pricebook2Id, Pricebook2.CurrencyIsoCode, CurrencyIsoCode from Order where Id = : orderId][0];
        if (ord.Pricebook2Id != null)
        {
            prboID = ord.Pricebook2Id;
        }
        currencyIsoCode = ord.CurrencyIsoCode;
        String query = 'select Id,name,Description,IsStandard, CurrencyIsoCode from Pricebook2  ';
        if (!String.isEmpty(prboID))
        {
            query +=  ' where Id =\'' + prboID + '\' ';
        }
        query += ' order by name limit 5000 ';
        system.debug(query);
        List < Pricebook2 > prboList_sele = Database.query(query);
        for (Pricebook2 prbo: prboList_sele)
        {
            PrboObj prob = new PrboObj();
            prob.isCheck = false;
            if (!String.isEmpty(prboID)) prob.isCheck = true;
            prob.prbo = prbo;
            prboList.add(prob);
        }
        downurl = Url.getSalesforceBaseUrl().toExternalForm() + '/apex/DownloadOrderItemTemplate?orId=' + orderId;
        System.debug(downurl);
    }
    //获取csv中的数据,封装成订单明细对象
    public void importCSVFile()
    {
        //先选择价格手册,如果没有选择则报错
        Set < String > strset_prbo = new Set < String > ();
        for (PrboObj prbo: prboList)
        {
            if (prbo.isCheck == true)
            {
                strset_prbo.add(prbo.prbo.Id);
                prboID = prbo.prbo.Id;
            }
        }
        if (strset_prbo.size() == 0)
        {
            ApexPages.Message errorMessage = new ApexPages.Message(ApexPages.severity.ERROR, '请先选择价格手册');
            ApexPages.addMessage(errorMessage);
            return;
        }
        if (strset_prbo.size() != 1)
        {
            ApexPages.Message errorMessage = new ApexPages.Message(ApexPages.severity.ERROR, '只能选择一个价格手册');
            ApexPages.addMessage(errorMessage);
            return;
        }
        //选择价格手册结束
        try
        {
            orderItemList = New List < OritList > ();
            //调用方法解析分级
            csvAsString = blobToString(csvFileBody, 'GBK');
            System.debug(csvAsString);
            csvFileLines = csvAsString.split('\n');
            System.debug('订单记录Id:' + system.currentPageReference().getParameters().get('id'));
            if(csvFileLines.size() < 2)
            {
                ApexPages.Message errorMessage = new ApexPages.Message(ApexPages.severity.ERROR, '没有需要导入的记录');
                ApexPages.addMessage(errorMessage);
                return;
            }
            //查找产品
            Set < String > strSet_produ = new Set < String > ();
            for (Integer i = 1; i < csvFileLines.size(); i++)
            {
                string[] csvRecordData = csvFileLines[i].split(',');
                Integer cssize = csvRecordData.size() - 1;
                if (cssize >= 3) strSet_produ.add(csvRecordData[3]);
                if (cssize >= 4) strSet_produ.add(csvRecordData[4]);
                strSet_produ.add(csvRecordData[0]);
            }
            //查询产品
             List < PricebookEntry > prenList = new List < PricebookEntry > ([
                    select Id, Product2Id, Product2.Name,Product2.ProductCode, UnitPrice, CurrencyIsoCode,Pricebook2Id from PricebookEntry
                    where Pricebook2Id in : strset_prbo and CurrencyIsoCode = : currencyIsoCode and (Product2.Name in: strSet_produ or Product2.ProductCode in: strSet_produ)]);
            Map < String, PricebookEntry > strMap_id = new Map < String, PricebookEntry > ();
            /*List < Product2 > prduList_sele = new List < Product2 > ([
                select Id, name, ProductCode from Product2 where name in : strSet_produ or ProductCode in : strSet_produ]);*/
            for (PricebookEntry prdu: prenList)
            {
                strMap_id.put(prdu.Product2Id, prdu);
                if (prdu.Product2.Name != null)
                {
                    strMap_id.put(prdu.Product2.Name, prdu);
                }
                if (prdu.Product2.ProductCode != null)
                {
                    strMap_id.put(prdu.Product2.ProductCode, prdu);
                }
            }
            //
            List < OrderItem > oritlist_sele = new List < OrderItem > ([select
                Id, Productline__c, Specification__c, Product2Id, Quantity,
                SubtotalF__c, Call_Guest__c, Description, Product_Name__c, UnitPrice2__c,
                OrderItemNumber, OrderId,PricebookEntryId
                from orderItem where id in : strSet_produ]);
            if (!oritlist_sele.isEmpty() && oritlist_sele[0].OrderId != orderId)
            {
                ApexPages.Message errorMessage = new ApexPages.Message(ApexPages.severity.ERROR, '订单明细关联的订单与本订单不符合');
                ApexPages.addMessage(errorMessage);
                return;
            }
            Map < String, OrderItem > strobjmap_orit = new Map < String, OrderItem > ();
            for (OrderItem orit: oritlist_sele)
            {
                strobjmap_orit.put(orit.Id, orit);
            }
            //构建订单明细
            Set < String > strset_produId = new Set < String > ();
            for (Integer i = 1; i < csvFileLines.size(); i++)
            {
                string[] csvRecordData = csvFileLines[i].split(',');
                Integer cssize = csvRecordData.size() - 1;
                System.debug(csvRecordData.size() + '===' + 'csvRecordData' + csvRecordData);
                //
                OritList orli = new OritList();
                if (cssize >= 3) orli.productCode = csvRecordData[3]; //产品代码
                if (cssize >= 8) orli.callGues = csvRecordData[8]; //客供否
                orli.productname = csvRecordData[4]; //品名
                OrderItem orderItem = new OrderItem();
                if (!string.isEmpty(csvRecordData[0]))
                {
                    orderItem = strobjmap_orit.get(csvRecordData[0]);
                    System.debug(orderItem);
                }
                else
                {
                    orderItem.OrderId = orderId;
                }
                //价格手册和产品赋值
                if (string.isEmpty(csvRecordData[1]))
                {
                    PricebookEntry pren = strMap_id.get(csvRecordData[3]) == null ? strMap_id.get(csvRecordData[4]) : strMap_id.get(csvRecordData[3]);//获取价格手册条目
                    if (pren == null) 
                    {
                        ApexPages.Message errorMessage = new ApexPages.Message(ApexPages.severity.ERROR, '第' + i + '行中的产品不在该价格手册下');
                        ApexPages.addMessage(errorMessage);
                        return;
                    }
                    String proId = strMap_id.get(csvRecordData[3]) == null ? strMap_id.get(csvRecordData[4]).Id : strMap_id.get(csvRecordData[3]).Id; //获取产品Id
                    orderItem.Product2Id = pren.Product2Id; //产品
                    orderItem.Product_Name__c = pren.Product2.Name;
                    orderItem.PricebookEntryId = pren.Id;
                    orderItem.UnitPrice2__c = pren.UnitPrice;
                    strset_produId.add(proId);
                }
                System.debug(csvRecordData[2]);
                if (cssize >= 2) orderItem.Productline__c = csvRecordData[2]; //产品项次
                System.debug(orderItem.Productline__c);
                if (cssize >= 5) orderItem.Specification__c = csvRecordData[5]; //规格型号
                if (cssize >= 6 && !String.isEmpty(csvRecordData[6])) orderItem.Quantity = Decimal.valueOf(csvRecordData[6]); //数量/面积 
                if (cssize >= 7 && !String.isEmpty(csvRecordData[7])) orderItem.SubtotalF__c = Decimal.valueOf(csvRecordData[7]); //卖价总计
                if (cssize >= 8) orderItem.Call_Guest__c = csvRecordData[8] == '是' ? true : false; //客供否      
                if (cssize >= 9) orderItem.Description = csvRecordData[9]; //行备注  
                orderItem.UnitPrice = 0;
                orli.orit = orderItem;
                orderItemList.add(orli);
            }
            /*List < PricebookEntry > prenList = new List < PricebookEntry > ([
                    select Id, Product2Id, Product2.Name, UnitPrice, CurrencyIsoCode from PricebookEntry
                    where Product2Id in : strset_produId and Pricebook2Id in : strset_prbo and CurrencyIsoCode = : currencyIsoCode]);
            Map < String, PricebookEntry > strmap_propri = new Map < String, PricebookEntry > ();
            for (PricebookEntry pren: prenList)
            {
                strmap_propri.put(pren.Product2Id, pren);
            }
            for (OritList oritli: orderItemList)
            {
                OrderItem orderItem = oritli.orit;
                if (orderItem.Id == null)
                {
                    System.debug(strmap_propri.get(orderItem.Product2Id));
                    if(strmap_propri.get(orderItem.Product2Id) != null)
                    {
                        orderItem.PricebookEntryId = strmap_propri.get(orderItem.Product2Id).id;
                        orderItem.UnitPrice2__c = strmap_propri.get(orderItem.Product2Id).UnitPrice;
                    }
                    orderItem.OrderId = orderId;
                }
            }*/
            csvFileBody = null;
        }
        catch (Exception e)
        {
            if(e.getMessage().contains('Argument cannot be null.'))
            {
                ApexPages.Message errorMessage = new ApexPages.Message(ApexPages.severity.ERROR, '引用了空值');
                ApexPages.addMessage(errorMessage);
                return;
            }
            ApexPages.Message errorMessage = new ApexPages.Message(ApexPages.severity.ERROR, '请选择csv文件或确认csv文件格式是否正确!' + e.getMessage());
            system.debug(e.getLineNumber());
            ApexPages.addMessage(errorMessage);
        }
    }
    //保存记录
    public PageReference save()
    {
        List < OrderItem > oritlist_upsert = new List < OrderItem > ();
        for (OritList oritli: orderItemList)
        {
            oritlist_upsert.add(oritli.orit);
        }
        upsert oritlist_upsert Id;
        return new PageReference('/' + orderId);
    }
    //取消
    public PageReference cancel()
    {
        return new PageReference('/' + orderId);
    }
    //将Blob转换成指定编码格式的String
    public static String blobToString(Blob input, String inCharset)
    {
        System.debug(String.valueOf(input));
        String hex = EncodingUtil.convertToHex(input);
        System.assertEquals(0, hex.length() & 1);
        final Integer bytesCount = hex.length() >> 1;
        String[] bytes = new String[bytesCount];
        for (Integer i = 0; i < bytesCount; ++i) bytes[i] = hex.mid(i << 1, 2);
        return EncodingUtil.urlDecode('%' + String.join(bytes, '%'), inCharset);
    }
}

<apex:page controller="ImportOrderItemController">
    <script type="text/javascript">
        function downfile(url){
            window.open(url);
        }
        
    script>
    <apex:pageBlock title="导入订单明细">
        <apex:form >
            <apex:pagemessages />
             <apex:pageBlockSection title="价格手册" columns="1" id="Section" >
                <apex:pageblocktable value="{!prboList}" var="prbo">
                    <apex:column headerValue="选择">
                        <apex:inputCheckbox value="{!prbo.isCheck}" />
                    apex:column>
                    <apex:column headerValue="{!$ObjectType['Pricebook2'].fields['name'].Label}" >
                     <apex:outputField value="{!prbo.prbo.Name} " />
                    apex:column>
                    <apex:column headerValue="{!$ObjectType['Pricebook2'].fields['Description'].Label}" >
                        <apex:outputField value="{!prbo.prbo.Description} " />
                    apex:column>
                    <apex:column headerValue="{!$ObjectType['Pricebook2'].fields['IsStandard'].Label}" >
                        <apex:outputField value="{!prbo.prbo.IsStandard} " />
                    apex:column>
                apex:pageblocktable>
            apex:pageBlockSection>

            <center>
                <apex:inputFile value="{!csvFileBody}"  filename="{!csvAsString}" style="margin-bottom:10px"/>
                <apex:comma
ndButton value="导入" action="{!importCSVFile}" style="margin-bottom:10px"/>
                <apex:commandButton value="下载模板" onclick="downfile('{!downurl}')"/>
            center>
            
            <apex:pageblocktable value="{!orderItemList}" var="order" id="orderitemall">
                <apex:column headerValue="{!$ObjectType['OrderItem'].fields['OrderItemNumber'].Label}" style="width: 11%">
                    <apex:outputField value="{!order.orit.OrderItemNumber} " />
                apex:column>
                <apex:column headerValue="{!$ObjectType['OrderItem'].fields['Productline__c'].Label}" style="width: 11%">
                    <apex:outputField value="{!order.orit.Productline__c} " />
                apex:column>
                <apex:column headerValue="产品代码" style="width: 11%">
                    <apex:outputText value="{!order.productCode} "/>
                apex:column>
               
                <apex:column headerValue="产品名称" style="width: 11%">
                    <apex:outputField value="{!order.orit.Product2Id} " />
                apex:column>
                <apex:column headerValue="{!$ObjectType['OrderItem'].fields['Product_Name__c'].Label}" style="width: 11%">
                    <apex:outputField value="{!order.orit.Product_Name__c} " />
                apex:column>
                <apex:column headerValue="{!$ObjectType['OrderItem'].fields['Specification__c'].Label}" style="width: 11%">
                    <apex:outputField value="{!order.orit.Specification__c} " />
                apex:column>
                <apex:column headerValue="{!$ObjectType['OrderItem'].fields['UnitPrice2__c'].Label}" style="width: 11%">
                    <apex:outputText value="{!order.orit.UnitPrice2__c} " />
                apex:column>
                <apex:column headerValue="{!$ObjectType['OrderItem'].fields['Quantity'].Label}" style="width: 11%">
                    <apex:outputField value="{!order.orit.Quantity} " />
                apex:column>
                <apex:column headerValue="{!$ObjectType['OrderItem'].fields['SubtotalF__c'].Label}" style="width: 11%">
                    <apex:outputText value="{!order.orit.SubtotalF__c} " />
                apex:column>
                <apex:column headerValue="{!$ObjectType['OrderItem'].fields['Call_Guest__c'].Label}" style="width: 11%">
                    <apex:outputText value="{!order.callGues} " />
                apex:column>
                <apex:column headerValue="{!$ObjectType['OrderItem'].fields['Description'].Label}" style="width: 11%">
                    <apex:outputField value="{!order.orit.Description} " />
                apex:column>
            apex:pageblocktable>
            
            <center>
                <apex:commandButton value="保存" action="{!save}" style="margin-right:50px;margin-top:50px"/>
                <apex:commandButton value="取消" action="{!cancel}"  style="margin-top:50px"/>
            center>
            
        apex:form>
    apex:pageBlock>
apex:page>

删除字符串中所有非字母或数字的字符

String str = 'sdf1sf**&';
String reg = '[^a-zA-Z0-9]';
str=str.replaceAll(reg,'');
System.debug(str);

查询语句中限制权限

SELECT Id, (SELECT LastName FROM Contacts),(SELECT Description FROM Opportunities) FROM Account WITH SECURITY_ENFORCED

获取选项列表值的依赖关系

//By SharSolutions
    public class MyPickListInfo
    {
        public String validFor;
    }

    public static Map<String, List<String>> getFieldDependencies(String objectName, String controllingField, String dependentField)
    {
        Map<String, List<String>> controllingInfo = new Map<String, List<String>>();

        Schema.SObjectType objType = Schema.getGlobalDescribe().get(objectName);

        Schema.DescribeSObjectResult describeResult = objType.getDescribe();
        Schema.DescribeFieldResult controllingFieldInfo = describeResult.fields.getMap().get(controllingField).getDescribe();
        Schema.DescribeFieldResult dependentFieldInfo = describeResult.fields.getMap().get(dependentField).getDescribe();

        List<Schema.PicklistEntry> controllingValues = controllingFieldInfo.getPicklistValues();
        List<Schema.PicklistEntry> dependentValues = dependentFieldInfo.getPicklistValues();

        for(Schema.PicklistEntry currControllingValue : controllingValues)
        {
            System.debug('ControllingField: Label:' + currControllingValue.getLabel());
            controllingInfo.put(currControllingValue.getLabel(), new List<String>());
        }

        for(Schema.PicklistEntry currDependentValue : dependentValues)
        {
            String jsonString = JSON.serialize(currDependentValue);

            MyPickListInfo info = (MyPickListInfo) JSON.deserialize(jsonString, MyPickListInfo.class);

            String hexString = EncodingUtil.convertToHex(EncodingUtil.base64Decode(info.validFor)).toUpperCase();

            System.debug('DependentField: Label:' + currDependentValue.getLabel() + ' ValidForInHex:' + hexString + ' JsonString:' + jsonString);

            Integer baseCount = 0;

            for(Integer curr : hexString.getChars())
            {
                Integer val = 0;

                if(curr >= 65)
                {
                    val = curr - 65 + 10;
                }
                else
                {
                    val = curr - 48;
                }

                if((val & 8) == 8)
                {
                    System.debug('Dependent Field: ' + currDependentValue.getLabel() + ' Partof ControllingField:' + controllingValues[baseCount + 0].getLabel());
                    controllingInfo.get(controllingValues[baseCount + 0].getLabel()).add(currDependentValue.getLabel());
                }
                if((val & 4) == 4)
                {
                    System.debug('Dependent Field: ' + currDependentValue.getLabel() + ' Partof ControllingField:' + controllingValues[baseCount + 1].getLabel());
                    controllingInfo.get(controllingValues[baseCount + 1].getLabel()).add(currDependentValue.getLabel());                    
                }
                if((val & 2) == 2)
                {
                    System.debug('Dependent Field: ' + currDependentValue.getLabel() + ' Partof ControllingField:' + controllingValues[baseCount + 2].getLabel());
                    controllingInfo.get(controllingValues[baseCount + 2].getLabel()).add(currDependentValue.getLabel());                    
                }
                if((val & 1) == 1)
                {
                    System.debug('Dependent Field: ' + currDependentValue.getLabel() + ' Partof ControllingField:' + controllingValues[baseCount + 3].getLabel());
                    controllingInfo.get(controllingValues[baseCount + 3].getLabel()).add(currDependentValue.getLabel());                    
                }

                baseCount += 4;
            }            
        } 

        System.debug('ControllingInfo: ' + controllingInfo);

        return controllingInfo;
    }

chatter提醒

List<ConnectApi.BatchInput> batchInputs = new List<ConnectApi.BatchInput>();    
ConnectApi.FeedItemInput feedItemInput = new ConnectApi.FeedItemInput();
ConnectApi.MentionSegmentInput mentionSegmentInput = new ConnectApi.MentionSegmentInput();
ConnectApi.MessageBodyInput messageBodyInput = new ConnectApi.MessageBodyInput();
ConnectApi.TextSegmentInput textSegmentInput = new ConnectApi.TextSegmentInput();
messageBodyInput.messageSegments = new List<ConnectApi.MessageSegmentInput>();
//拼接上链接
ConnectApi.EntityLinkSegmentInput entityLinkSegmentInputOpportunity = new ConnectApi.EntityLinkSegmentInput();
entityLinkSegmentInputOpportunity.entityId = 要链接的记录的ID;  
messageBodyInput.messageSegments.add(entityLinkSegmentInputOpportunity);
mentionSegmentInput.id = 要@的人的ID;
messageBodyInput.messageSegments.add(mentionSegmentInput);
textSegmentInput.text = 发送的内容;
messageBodyInput.messageSegments.add(textSegmentInput);
feedItemInput.body = messageBodyInput;
feedItemInput.feedElementType = ConnectApi.FeedElementType.FeedItem;
feedItemInput.subjectId =关联的记录;
feedItemInput.visibility = ConnectApi.FeedItemVisibilityType.AllUsers;//设置该chatter的权限(ConnectApi.FeedItemVisibilityType.InternalUsers默认,只有销售云中的用户可见;ConnectApi.FeedItemVisibilityType.AllUsers其他云的用户也可见)
ConnectApi.BatchInput batchInput = new ConnectApi.BatchInput(feedItemInput);
batchInputs.add(batchInput);
ConnectApi.ChatterFeeds.postFeedElementBatch(Network.getNetworkId(), batchInputs);

Salesforce Apex开发笔记_第6张图片

获取自定义标签


Apex: String someLabel = System.Label.Label_API_Name;

从接口中下载文件保存到salesforce

/**
 * 从接口中下载文件,需要获取到文件下载的链接和文件的名称
 * @param fileLink [文件链接]
 * @param fileName [文件名称(带后缀名)]
 * @param parid    [要关联的记录ID]
 * @param ownerid  [文件的所有人ID]
 */
@future(callout = true)
public static void esbCalloutTest(String fileLink, String fileName, Id parid, Id ownerid)
{
    try
    {
        //发送请求
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint(fileLink);
        req.setTimeout(60000);
        req.setMethod('GET');
        HttpResponse res1 = h.send(req);
        Blob body = res1.getBodyAsBlob();
        //保存文件
        Attachment att = new Attachment();
        att.Name = fileName;
        att.Body = body;
        att.ContentType = '';
        att.ParentId = parid;
        att.OwnerId = ownerid;
        insert att;
    }
    catch (Exception e)
    {
        system.debug(e.getLineNumber() + e.getMessage());
    }
}

获取文件

//附件
            List < ContentDocumentLink > cdllist = [select ContentDocumentId, LinkedEntityId from ContentDocumentLink where LinkedEntityId = : 对象ID];
            Set < String > cdIdSet = new Set < String > ();
            for (ContentDocumentLink cdl: cdllist)
            {
                cdIdSet.add(cdl.ContentDocumentId);
            }
	//获取文件名称
            List < ContentDocument > cdclist = [select Id, OwnerId, Owner.Name, Owner.EmployeeCode__c, Title, CreatedDate FROM ContentDocument where Id in : cdIdSet];
	//获取链接
            List < ContentDistribution > cdlist = [select ContentDocumentId, DistributionPublicUrl, ContentDownloadUrl from ContentDistribution where ContentDocumentId in : cdIdSet];
	//获取文件的类型
            List < ContentVersion > covelist = new List < ContentVersion > ([select id, ContentDocumentId, FileExtension from ContentVersion where ContentDocumentId in : cdIdSet]);
            Map < Id, String > idsetmap_docufile = new Map < Id, String > ();
            for (ContentVersion cove: covelist)
            {
                idsetmap_docufile.put(cove.ContentDocumentId, cove.FileExtension);
            }
            List < SettlementCode_Entity.AttAchmentList > attlist = new List < SettlementCode_Entity.AttAchmentList > ();
            for (ContentDocument cdc: cdclist)
            {
                for (ContentDistribution cd: cdlist)
                {
                    if (cdc.Id == cd.ContentDocumentId)
                    {
                        attFile atli = new attFile();
                        atli.FileName = cdc.Title + '.' + idsetmap_docufile.get(cdc.Id);
                        atli.URL = cd.ContentDownloadUrl;
                        atfilist.add(atli);
                    }
                }
            }
            frjs.AttachFile = atfilist;

获取链接中拼接的元素

apexpages.currentPage().getParameters().get('applicationId');

事件中的出席者 Attendees 字段查询

出席者 Attendees 是一个对象,而不是一个字段
对象:EventRelation

SELECT Id, Relationid, Relation.name, EventId,isinvitee FROM EventRelation where isinvitee = true

isinvitee == true 为出席者

触发器一个事物进入两次

https://help.salesforce.com/articleView?id=000324749&type=1&mode=1

Add a static boolean variable to a class, and check its value within the affected triggers.

public class HelperClass { public static boolean firstRun = true; }



trigger affectedTrigger on Account (before delete, after delete, after undelete) 
{ 
	if(Trigger.isBefore)
	{       
		if(Trigger.isDelete)
		{            
			if(HelperClass.firstRun)
			{                
				Trigger.old[0].addError('Before Account Delete Error');                
				HelperClass.firstRun=false;            
			}       
		} 
	} 
}

根据列表视图获取数据

Yes you can!

First get the sObjectType of the ListView by querying like

SELECT Id, sObjectType FROM ListView WHERE Id = :yourId

Then simply make a callout to your own org with a URL like

/services/data/v40.0/sobjects/[sObjectType]/listviews/[yourId]/describe

You will get back an object with (amongst others) a query attribute. Use that to query your records.

Making a callout to your own org has become even easier since spring 19 because you don’t need a Remote Site Setting and can use UserInfo.getSessionId() even in async jobs.

Good luck!

https://salesforce.stackexchange.com/questions/167009/can-we-access-all-listview-records-of-any-object-using-listview-id

验证码存值

方法一:把生成的验证码保存在一个静态变量中,然后设置一个缓存时间,二次传入的时候
把生成的验证码存放在一个静态变量中

public static RS_CacheManager cacheManager = new RS_CacheManager(false);
 /**
	     * 获取验证码
	      */
public static String getCaptcha(String mobile){
    if(String.isBlank(mobile)){
        return null;
    }
    System.debug('RS_SessionCache.getCaptcha:'+mobile);
    RS_CacheManager cacheManager = RS_SessionCache.cacheManager;
    String captcha = (String)cacheManager.get(RS_Constants.CACHE_KEY_CAPTCHA + mobile);
    return captcha;
}

时间查询

https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_soql_select_dateformats.htm

客户中标准生日字段
查询今天的数据是如果用 = today 或 yesterday 时只匹配月份和日期,不匹配年份
Salesforce Apex开发笔记_第7张图片

TimeZone tz = UserInfo.getTimeZone();
DateTime dt = Datetime.now();
system.debug('gmt时间 ' + dt);
system.debug('正确时间' + dt.format());
system.debug('Offset ' + tz.getOffset(dt)/1000);
system.debug('Formatted Time ' + dt.addSeconds((tz.getOffset(dt)/1000)));

sql的分组查询

使用 GROUP BY 进行分组,并且搜索出来的字段仅能是Id和用于分组的字段。


List<AggregateResult> agrResult = new List<AggregateResult>([SELECT Status FROM Case GROUP BY Status]);//
    	

注意点:不能超过2000条数据,limit 2000

防止batch进入触发器

System.isSchedulable()

https://salesforce.stackexchange.com/questions/29520/how-to-prevent-a-trigger-firing-during-a-batch-job

batch调用接口

 Database.AllowsCallouts

Sql 语句的 多选类别查询

SELECT Id, MSP1__c from CustObj__c WHERE MSP1__c includes ('AAA;BBB','CCC')

市场活动成员

Salesforce Apex开发笔记_第8张图片

数字格式化成货币格式

Decimal rA = 1298763.86;
Integer ra2 = Integer.valueOf(rA);
List<String> args = new String[]{'0','number','###,###,##0.00'};
String s = String.format(ra2.format(), args);
System.debug(s);

获取富文本区域的图片链接

Account record = [select Id,textlong__c from Account where id = '0010K00002I3aCI'];
// use reluctant regex to match each image tag individually
// https://docs.oracle.com/javase/tutorial/essential/regex/quant.html
Matcher imgMatcher = Pattern.compile( '<img(.+?)>' ).matcher( record.textlong__c );

// iterate each image tag found
while ( imgMatcher.find() ) {

    // get the image tag html
    String imageTag = imgMatcher.group();
    System.debug( 'imageTag=' + imageTag );

    // get the value of the src attribute
    // the leading space is significant to avoid other attributes like data-cke-saved-src
    String imageURL = imageTag.substringBetween( ' src="', '"' );
    System.debug( 'imageURL=' + imageURL );

    // if url contained parameters they might be html escaped, unescape them
    // or, more conservatively, replace '&' with '&'
    String decodedURL = imageURL.unescapeHtml4();
    System.debug( 'decodedURL=' + decodedURL );

    // note, as of API 34.0 or later, getContent() is considered an http callout
    // so take that into consideration for your unit tests and governor limits
    // https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/apex_System_PageReference_getContent.htm
    PageReference page = new PageReference( decodedURL );
    Blob b = page.getContent();
    System.debug( 'blob=' + b );

    System.debug( 'Enjoy your Blob, save it as a Document, ContentVersion, whatever!' );

    System.debug(''); // I like blank lines in my logs, easier to scan/read =)

}

计算工作日

Date selectedDate =  Date.today();
Date lastDate = selectedDate.toStartOfMonth().addDays(Date.daysInMonth(selectedDate.year(), selectedDate.month()) - 1);
System.debug(lastDate);
BusinessHours bh = [SELECT Id FROM BusinessHours WHERE IsDefault=true];
System.debug(BusinessHours.isWithin(bh.id, lastDate));

BusinessHours.isWithin(bh.id, lastDate) 如果这一天是工作日,那么则返回true,如果不是,则返回false

需先在系统设置标准的工作时间
Salesforce Apex开发笔记_第9张图片
获取倒数第二个工作日

Date selectedDate =  Date.today();
Date lastDate = selectedDate.toStartOfMonth().addDays(Date.daysInMonth(selectedDate.year(), selectedDate.month()) - 1);
System.debug(lastDate);
BusinessHours bh = [SELECT Id FROM BusinessHours WHERE IsDefault=true];
System.debug(BusinessHours.isWithin(bh.id, lastDate));
Integer i = 0;
Date last2day;
while (i < 2)
{
    if (BusinessHours.isWithin(bh.id, lastDate)) 
    {
        i++;
    }
    last2day = lastDate;
    lastDate = lastDate.addDays(-1);
}
System.debug(last2day);

是否可以修改标准接口每批的数量

不可以。SF的限制

https://salesforce.stackexchange.com/questions/300961/is-it-possible-to-change-the-size-of-the-auto-chunked-batches-in-bulk-api

打包类型

AI Application config
Action
Action Link Group Template
Allow URL for Redirects
Apex Class
Apex Sharing Reason
Apex Trigger
App
Approval Process
Asset File
Assignment Rule
Assistant Recommendation Type
Aura Component Bundle
Auth. Provider
Auto-Response Rule
Button or Link
CORS Allowed Origin List
Call Center
Case Keywords Priority
Channel Menu Deployment
Chat Agent Configuration
Chat Blocking Rule
Chat Button
Chat Deployment
Classic Letterhead
Communication Channel Layout
Compact Layout
Content Security Policy Trusted Site
Custom Console Component
Custom Data Type
Custom Field
Custom Help Menu Section
Custom Index
Custom Label
Custom Metadata Type
Custom Notification Type
Custom Object
Custom Permission
Custom Report Type
Custom Setting
Dashboard
Data Service
Document
Duplicate Rule
EclairNG Map GeoJson
Email Service
Email Template
Embedded Service Deployment
Entitlement Process
Entitlement Template
Entity Implements
Escalation Rule
Event Subscription
Extension
External Data Source
External Service Registration
Feed Filter
Field Mapping
Field Set
Flow Definition
Folder
Global Value Set
Group
Home Page Component
Home Page Layout
Inbound Network Connection
Knowledge Action
Language Translation
Lightning Bolt
Lightning Community Template
Lightning Community Theme
Lightning Experience Theme
Lightning Message Channel
Lightning Page
Lightning Web Component Bundle
List View
ML Data Definition
ML Prediction Definition
Managed Content Type
Matching Rule
Microsoft® Outlook® Web App Domain
Milestone
Named Credential
Network
Outbound Network Connection
Page Layout
Path Assistant
Permission Set
Permission Set Group
Platform Cache Partition
Platform Event Channel
Platform Event Channel Member
Platform Event Subscriber Configuration
Post Template
Prompt
Queue
Recommendation Strategy
Record Type
RecordAction Deployment
Remote Site
Report
Reporting Snapshot
Role
S-Control
Security Custom Baseline
Send Action
Sensitive Data Rule
Sharing Criteria Rule
Sharing Guest Rule
Sharing Owner Rule
Sharing Set
Site.com
Skill
Static Resource
Tab
User Provisioning Config
Validation Rule
Visualforce Component
Visualforce Page
Workflow Email Alert
Workflow Field Update
Workflow Outbound Message
Workflow Rule
Workflow Task
Zone

在list中获取任意个

List<String> availableValues = new List<String>{'17','21','33','44','55'};
Integer listSize = availableValues.size() - 1;
Integer randomNumber = Integer.valueof((Math.random() * listSize));
String randomString= availableValues[randomNumber];
System.debug('randomString is'+randomString);

Metadata

删除

MetadataService.MetadataPort service = new  MetadataService.MetadataPort();
List<String> recordsToDelete = new List<String>();
recordsToDelete.add('My_Custom_Type.record1');
service.deleteMetadata('CustomMetadata', recordsToDelete);

From https://salesforce.stackexchange.com/questions/229406/how-to-delete-custom-metadata-records-via-apex

增删改权限判断

The DescribeSObjectResult Class contains methods for describing sObjects.
Important Methods for DescribeSObjectResult. All are instance methods.
fields
Follow fields with a field member variable name or with the getMap method.

getChildRelationships()

Returns a list of child relationships, which are the names of the sObjects that have a foreign key to the sObject being described.

getLabel()

Returns the object’s label, which may or may not match the object name.

getLabelPlural()

Returns the object’s plural label, which may or may not match the object name.

getName()

Returns the name of the object.

getSobjectType()

Returns the Schema.SObjectType object for the sObject. You can use this to create a similar sObject.

isAccessible()

Returns true if the current user can see this object, false otherwise.

isCreateable()

Returns true if the object can be created by the current user, false otherwise.

isCustom()

Returns true if the object is a custom object, false if it is a standard object.

isCustomSetting()

Returns true if the object is a custom setting, false otherwise.

isDeletable()

Returns true if the object can be deleted by the current user, false otherwise.

isQueryable()

Returns true if the object can be queried by the current user, false otherwise

isSearchable()

Returns true if the object can be searched by the current user, false otherwise.

isUndeletable()

Returns true if the object cannot be undeleted by the current user, false otherwise.

isUpdateable()

Returns true if the object can be updated by the current user, false otherwise.

From https://www.sfdcmeet.com/development/apex-in-salesforce/dynamic-apex-salesforce/

Retry

Platform Events Developer Guide | Retry Event Triggers with EventBus.RetryableException (salesforce.com)

https://developer.salesforce.com/docs/atlas.en-us.platform_events.meta/platform_events/platform_events_subscribe_apex_refire.htm

第二种方法:
queueable job来retry
GitHub - jantaks/salesforce-apex-retry: Retry framework for Salesforce applications

custom metadata type

List<Games__mdt> mcs = Games__mdt.getAll().values();
boolean textField = null;
if (mcs[0].GameType__c == 'PC') {
   textField = true;
}
system.assertEquals(textField, true);
  • getAll()
    Returns a map containing custom metadata records for the specific custom metadata type. The map’s keys are the IDs of the records and the map’s values are the record sObjects.
  • getInstance(recordId)
    Returns a single custom metadata type record sObject for a specified record ID.
  • getInstance(developerName)
    Returns a single custom metadata type record sObject for a specified developerName field of the custom metadata type object.
  • getInstance(qualifiedApiName)
    Returns a single custom metadata type record sObject for a qualified API name.
    参考:https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_custom_metadata_types.htm

User Role 角色

public static set<Id> getSubordinateRoles(Id roleId) {
    map<Id, set<Id>> parentAndChildren = new map<Id, set<Id>>();
    set<Id> children;
    for(UserRole ur : [select Id, ParentRoleId from UserRole]) {
        children = parentAndChildren.containsKey(ur.ParentRoleId) ? parentAndChildren.get(ur.ParentRoleId) : new set<Id>();
        children.add(ur.Id);
        parentAndChildren.put(ur.ParentRoleId, children);
    }
    return getSubordinateRoles(role, parentAndChildren);
}
public static set<Id> getSubordinateRoles(Id roleId, map<Id, set<Id>> parentAndChildren) {
    set<Id> subordinateRoles = new set<Id>();
    set<Id> remainingSubordinateRoles = new set<Id>();
    if(parentAndChildren.containsKey(roleId)) {
        subordinateRoles.addAll(parentAndChildren.get(roleId));
        for(Id subRoleId : subordinateRoles) {
            remainingSubordinateRoles.addAll(getSubordinateRoles(subRoleId, parentAndChildren));
        }
    }
    subordinateRoles.addAll(remainingSubordinateRoles);
    return subordinateRoles;
}

field set 字段集

Map<String, Schema.FieldSet> FsMap =  Schema.SObjectType.Account.fieldSets.getMap();
Schema.DescribeSObjectResult d =  Account.sObjectType.getDescribe();
Map<String, Schema.FieldSet> FsMap =  d.fieldSets.getMap();
Schema.FieldSet fs1 = Schema.SObjectType.Account.fieldSets.getMap().get('field_set_name');
Schema.FieldSet fs2 = Schema.SObjectType.Account.fieldSets.field_set_name;

https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_fieldsets_describe.htm

当字段名是一个String值时获取记录对应改字段的值

Account acc = [select Id,(select id from Contacts) from Account limit 1];
system.debug(acc.get('ID'));
system.debug(acc.getSObjects('Contacts'));

实际效果

16:52:32.30 (74317403)|USER_DEBUG|[2]|DEBUG|001xxxxxxxxxxxxxxx
16:52:32.30 (74757995)|USER_DEBUG|[3]|DEBUG|(Contact:{AccountId=001xxxxxxxxxxxxxxx, Id=003xxxxxxxxxxxxxxx})

赋值:

sObject acc = [select lastname, firstname from account limit 1];
system.debug('输出' + acc);
acc.put('lastname','test');
system.debug('输出' + acc);

实际效果

17:24:35.31 (53438763)|USER_DEBUG|[2]|DEBUG|输出Account:{LastName=er, FirstName=er, Id=0010T00000MT41uQAD}
17:24:35.31 (53702076)|USER_DEBUG|[4]|DEBUG|输出Account:{LastName=test, FirstName=er, Id=0010T00000MT41uQAD}

在apex中新建或更新custom metadata type record

public class CreateUpdateMetadataUtils implements Metadata.DeployCallback {
    
    public void handleResult(Metadata.DeployResult result, Metadata.DeployCallbackContext context) {
        if (result.status == Metadata.DeployStatus.Succeeded) {
            System.debug(' success : '+ result);
        } else {
            System.debug(' fail : '+ result);
        }
    }
    
    public static void createUpdateMetadata(String fullName, String label, Map<String, Object> fieldWithValuesMap){
        Metadata.CustomMetadata customMetadata =  new Metadata.CustomMetadata();
        customMetadata.fullName = fullName;
        customMetadata.label = label;
        
        for(String key : fieldWithValuesMap.keySet()){
            Metadata.CustomMetadataValue customField = new Metadata.CustomMetadataValue();
            customField.field = key;
            customField.value = fieldWithValuesMap.get(key); 
            customMetadata.values.add(customField);
        }
        
        Metadata.DeployContainer mdContainer = new Metadata.DeployContainer();
        mdContainer.addMetadata(customMetadata);
        CreateUpdateMetadataUtils callback = new CreateUpdateMetadataUtils();
        Id jobId = Metadata.Operations.enqueueDeployment(mdContainer, callback);
    }
}

需要的system permission

<userPermissions>
        <enabled>trueenabled>
        <name>ApiEnabledname>
    userPermissions>
    <userPermissions>
        <enabled>trueenabled>
        <name>CustomizeApplicationname>
    userPermissions>
    <userPermissions>
        <enabled>trueenabled>
        <name>ManageCustomPermissionsname>
    userPermissions>
    <userPermissions>
        <enabled>trueenabled>
        <name>ManageTranslationname>
    userPermissions>
    <userPermissions>
        <enabled>trueenabled>
        <name>ModifyMetadataname>
    userPermissions>
    <userPermissions>
        <enabled>trueenabled>
        <name>ViewRolesname>
    userPermissions>
    <userPermissions>
        <enabled>trueenabled>
        <name>ViewSetupname>
    userPermissions>

sql查询时特殊字符识别

String.escapeSingleQuotes(str);
String name = 'aa\'dd';
String sql = 'SELECT Id FROM Account WHERE Name = \'' + String.escapeSingleQuotes(name) + '\'';
List<Account> acclist = Database.query(sql);

当name字段含特使符号时,如果直接查询,则会报错。

salesforce limit

Description Cumulative Cross-Namespace Limit
Total number of SOQL queries issued 1,100
Total number of records retrieved by Database.getQueryLocator 110,000
Total number of SOSL queries issued 220
Total number of DML statements issued 1,650
Total number of callouts (HTTP requests or web services calls) in a transaction 1,100
Total number of sendEmail methods allowed 110
Description Synchronous Limit Asynchronous Limit
Total number of SOQL queries issued1 100 200
Total number of records retrieved by SOQL queries 50,000
Total number of records retrieved byDatabase.getQueryLocator 10,000
Total number of SOSL queries issued 20
Total number of records retrieved by a single SOSL query 2,000
Total number of DML statements issued2 150
Total number of records processed as a result of DML statements,Approval.process, ordatabase.emptyRecycleBin 10,000
Total stack depth for any Apex invocation that recursively fires triggers due toinsert,update, ordeletestatements3 16
Total number of callouts (HTTP requests or web services calls) in a transaction 100
Maximum cumulative timeout for all callouts (HTTP requests or Web services calls) in a transaction 120 seconds
Maximum number of methods with thefutureannotation allowed per Apex invocation 50 0 in batch and future contexts; 1 in queueable context
Maximum number of Apex jobs added to the queue withSystem.enqueueJob 50 1
Total number ofsendEmailmethods allowed 10
Total heap size4 6 MB 12 MB
Maximum CPU time on the Salesforce servers5 10,000 milliseconds 60,000 milliseconds
Maximum execution time for each Apex transaction 10 minutes
Maximum number of push notification method calls allowed per Apex transaction 10
Maximum number of push notifications that can be sent in each push notification method call 2,000
Maximum number ofEventBus.publishcalls for platform events configured to publish immediately 150
mber ofEventBus.publishcalls for platform events configured to publish immediately 150

加密

  1. List View: we can’t sort by the records with the encrypted fields and not supported those operations like “contains”/“Starts with” in the filter

  2. Sharing rule: we can’t use the encrypted fields in the criteria-based sharing rules.

  3. Report: we can’t sort records in list views by fields that contain encrypted data.

  4. Apex class/SOQL: don’t support below statements:

    • SOQL GROUP BY Statements
    • SOQL LIKE and STARTS WITH Statements
    • SOQL ORDER BY Statements
  5. Case-sensitive and case-insensitive deterministic encryption schemes support compound fields, but only with individual column queries.
    Such as: after encrypt field “Contact.name”, this is a combined field, which name = firstname + lastname.
    And only below query support: select id from Contact where firstname = ‘xxx’ and lastname = ‘xxx’

SOSL查询

  • 查询结果只返回2000条。
  • 无法对某个字段进行搜索,只能对某类型的字段进行搜索。
    比如:需搜索Last Name包含’Test’的数据,查询是会对Account中的Last Name、Frist Name、Name字段进行查询,有查询结果后再进行二次处理。
 a.字母:搜索结果只返回以每个单词以搜索词为开头的数据(每个单词的是指用空格或者其他类型字符隔开的字母)
	比如:有以下Account
		Account1: Last Name = New Account
		Account2: Last Name = NewAccount
		Account3: Last Name = New 123Account
		Account4: Last Name = New 客户Account
	在Last Name搜索框中搜索Account
	返回结果:Account1,Account3,Account4
b.数字:搜索结果只返回以每串数字以搜索词为开头的数据(每串数字的是指用空格或者其他类型字符隔开的字母)
	比如:有以下Account
		Account1: Last Name = 123New Account; Email = [email protected]
		Account2: Last Name = 456123NewAccount; Email = [email protected]
		Account3: Last Name = New99@123Account; Email = [email protected]
		Account4: Last Name = New客123户Account; Email = [email protected]
	在Last Name搜索框中搜索123
	返回结果:Account1,Account3,Account4
	在Email中搜索框中搜索123
	返回结果:Account1,Account3,Account4
c.中文:无限制,只要系统有匹配的都可以返回。
	比如:有以下Account
		Account1: Last Name = 新客户旧客户
		Account2: Last Name = 今天天气不错
		Account3: Last Name = new客户
	在Last Name中搜索'客户'
	返回结果:Account1,Account3

导致的影响:

  • 只影响模糊查询。精确不影响
  • 返回数据量太少,可能导致查询结果不是User想要的结果
  • 输入的搜索词必须是各类型的字符的开头,否则搜索不出想要的数据。

##判断用户是否在某个custom permission中

Boolean hasCustomPermission = FeatureManagement.checkPermission('your_custom_permission_api_name');

https://developer.salesforce.com/docs/atlas.en-us.securityImplGuide.meta/securityImplGuide/custom_perms_overview.htm

判断字段或者对象是否有权限的公共方法

/**
    * @description Public method for updating data, determines if have permission before updating.
    * @param objectName need update record object name
    * @param updatelist update record list
    **/
    public static void checkObjectPermissionAndUpdateRecord(String objectName, List<sObject> updatelist){
        SObjectType objectType = ((SObject)Type.forName('Schema', 'Account').newInstance()).getSObjectType();
        if (updatelist != null && !updatelist.isEmpty() && objectType.getDescribe().isUpdateable()){
            update updatelist;        
        }
    }

查询数据时查询isDeleted的数据

在sql语句中加上 ALL ROWS

List<Account> acclist = [SELECT id FROM Account WHERE IsDeleted = true  ALL ROWS];

你可能感兴趣的:(salesforce开发笔记,java)