Salesforce的Auto Number

在Salesforce中新建Object的时候,可以对Name选择Auto Number,即自动编号。如果没有仔细阅读说明的话,会有一个很容易让人迷惑的地方。

在选择时候,Salesforce提供的示例为 示例:  A-{0000}。

那么问题来了,假设我如示例一样设定了4个0,那么当我的数据编号已经到达了A-9999会怎么样呢?

真实情况是,什么都不会发生,A-10000会被正常创建,A-10001也会被正常创建。

原因是这样的,A-{0000}的意思,是至少要有4位数字,不足则补零。例如,第99条数据的Name为A-0099。就是说,这个格式只是用来标注补零的位数的。。。不是用来限制编号最大位的。。。

然后,在设定是还可以输入开始数字,假设我设定从99999开始呢? 还是没关系。但如果设定的开始数字为1,000,000,000以上,则会告诉你,不能大于这个数。

OK,那我设为999,999,999。接下来创建数据会怎样呢?

没错,A-1000000000会被正常创建,在建一条,A-1000000001也出来了。。。。。。

所以不用担心编号用光的事情了。200多位。。。我觉得有生之前都不一定用得没了。。

Salesforce也有Explain了

Explain在各大数据库里,是调式SQL的利器。
虽然众所周知,Salesforce底层用的是Oracle。但从来没有开放过调用Explain的方法。

终于,有变化了!
目前作为一个beta特性,Salesforce将Explain放进了REST API
不过比较蛋疼的是,返回的是json,需要自己处理下。由于是beta特性,所以Salesforce不做任何技术支持。

<?php 
// Get your token via REST API 
$token = getToken(); 
$remote_server = "https://****your instance name****.salesforce.com/services/data/v37.0/query/?explain=*****your soql*****"; 
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remote_server); 
curl_setopt($ch, CURLOPT_POST, false); 
$header[] = "Authorization:Bearer " . $token; 
curl_setopt($ch, CURLOPT_HTTPHEADER,$header); 
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 
$data = curl_exec($ch); 
curl_close($ch); 
echo $data; 
?>

// 2016-09-28 Update1

其实在Salesforce Developer Console中早就有这个功能了。。。但是对于分析SOQL的瓶颈还是很有帮助的。

Salesforce中一条数据占多大存储空间

如果把Salesforce视为一个数据库的话,它与其他牌子的数据库不大一样。
按理说,不同的表因为字段数量不同,字段多的应该比字段少的占用空间要多。

但是Salesforce却无视字段数量,就是说字段数量不会影响到占用空间。
大多数情况,每条数据占用空间为2KB
但是还有例外

Leads — 2KB
Contacts — 2KB
Accounts — 2KB
Person Accounts – 4KB
Opportunities — 2KB
Forecasts — 2KB
Events — 2KB
Tasks — 2KB
Cases — 2KB
Case Team Member – 2KB
Solutions — 2KB
Notes — 2KB
Custom Reports — 2KB
Campaigns – 8KB
Campaign Members – 1KB
Contracts – 2KB
Google Docs – 2KB
Quotes – 2KB
Tags: unique tags – 2KB
Custom Objects – 2KB
Quote Template Rich Text Data – 2KB
Articles – 4KB

所以在进行存储空间估算的时候要注意例外的SObject。

Salesforce中简单的进行Callout的Scheduler

global class MyScheduler implements Schedulable{
    global void execute(SchedulableContext SC){
        CallOut.doCallout();
    }
}
public class CallOut{
    @future(callout=true)
    public static void doCallout(){
               HttpRequest req = new HttpRequest();
        HttpResponse res = new HttpResponse();
        Http http = new Http();
        req.setEndpoint(endPoint);
        req.setMethod('POST');
        req.setCompressed(false);
        req.setBody('');
        req.setHeader('Content-Type', 'application/x-www-form-urlencoded');
        res = http.send(req);
        // do something with res.
        }
}

Task上的IsArchive字段

Salesforce中会对符合条件的SObject进行自动的Archive。就是压缩。

官方文档的描述中,主要的条件为Closed超过365天。系统会自动的进行Archive。

具体的体现在,Task上会有一个字段叫做isArchived。如果task被系统Archive,此字段便会设为True。同时,此条数据无法在report中进行显示。但可以用Query All的方式获取。

以上是背景资料。

继续调查了一下,发现就算是被Archive,仍然占据储存空间。那么,是否与正常的数据占用的空间大小一致呢?还有,系统会在什么时候进行标记工作呢?是不是与储存空间的使用情况相关呢?

我进行了如下试验:

在一个干净的Org里,开启了Createddate可写,然后插入了一定量的状态为Connect/Closed的Task。确定IsClosed已为True。之后等。

结果:等待一宿之后,IsArchived字段毫无变化,可确定频率不是每日。

To Be Continue…

// 2016-06-08 Update1

经过和Salesforce技术支持的各种撕逼深度沟通,目前可以确认的是:

  1. 在Salesforce环境中的Storage Usage页面看到的统计数据是所有未被删除数据(正常数据+被Archive掉的数据)。总结一下就是说,Archive掉了仍然和正常数据一样占用空间(然后在Report里还变的不可见了,不加Query all也检索不到了,Salesforce搞毛线?)
  2. 被Archive只是代表被更改了一个状态位,并不影响储存(与正常数据一样占用2KB)
  3. Archive只针对Task等有限的几张表,具体的实施时间点是在每周六大概,系统自动执行。

这样的话,我们在清理task数据的时候,一定要用query all,并加上条件isdeleted=false。才是全部的目标范围。

Salesforce与Trigger的故事续篇

Selseforce与Trigger又有新的故事发生了。
目前没有官方文档对此现象有相关描述。

具体现象是这样的。
假设有一个Object叫做ObjectA,上面有个字段A__c是Lookup字段,比如Lookup Contact。
还有一个字段B__c是公式字段,公式的内容是A__r.Account.Id。

问题出在我们在ObjectA的Before Insert Trigger上,做了A__c的赋值操作。
如果我们在触发Trigger的时候,所插入的数据并没有对A__c进行过任何操作,在Trigger里对A__c进行赋值的话,在Trigger里取B__c的值居然是为空的。

如果我们在触发Trigger的时候,对A__c进行赋值,那么在Trigger里再次对A__c进行赋值,在Trigger里取得B__c的值的话,呵呵呵呵呵呵,里面居然是在触发前设定的那个Contact关联的Account的ID。就是说,在Trigger里更改A的值,并没有对公式字段B造成影响。

推断如下,
因为公式字段的内容为__r,所以需要在后台进行一次查询,但是因为在Trigger里,本条数据虽然还没有插入数据库,但是还是被锁住了,导致无法及时的更新公式字段的值。

或者,只要是进入了Apex代码范围,所有公式字段皆无法进行实时更新。

// Update1

已证实,只要进入Apex范围公式就不会更新,但会保留进入之前的计算结果。

// Update2 2018-01-12

写这篇文章的时候,貌似sfdc刚刚release了recalculate formula的函数。所以当时傻乎乎的以为没办法。现在知道了,直接调用SObject.recalculateFormulas()方法就好了。不过需要注意的是,cross-object的formula并不会被重新计算。

关于Trigger与Workflow的故事

Salesforce中,一个动作会触发一系列的处理。

在Salesforce官方文档里,有关于各个处理的处理顺序的描述。执行顺序的官方描述

其中有这么一种情况,如果有个Workflow的行为是更新字段的值,然后在此Object中有一个After Trigger,包括Insert与Update。

在官方文档的描述里,After Trigger是优先于Workflow的。

这样的话,会出现一种现象,当新建了一条符合workflow条件的数据的时候,Trigger中的Insert和Update会被先后执行。但是Trigger内部的话并不会出现这种情况,并且After Trigger是不允许更新本条数据的。

Workflow与Trigger的关系要捋清,要慎用。

// Update1 2016-06-08

Flow Chart