在去年年初,我们曾经讨论过Salesforce 15位ID与18位ID的话题(《关于salesforce的15位id与18位id》)。
那时候简单介绍了Salesforce的Id的组成,比如头三位为prefix,4到6位为instance code,校检位,18位ID的特性是case safe而不是大小写不敏感,等等。
那么有没有想过,Salesforce是如何知道某个字符串是不是合法的ID的呢?
虽然Apex里有Id与String两种数据类型,但是两者之间的关系却是如此暧昧与纠缠不清。
很多时候本应当使用Id型变量储存Id值,我们用String型变量去储存,然而也不会出问题。
再比如说,在SOQL中,我们在where语句中可以这么写…WHERE Id = ‘0016F000035LFXo ‘…干脆就是用的字符串。
如果是在Apex中,我们也可以使用变量…WHERE Id =: myId …,这里的变量myId无论是Id型还是String型也都不会有问题。所以粗略的看,似乎当作是一回事也没关系。
但是,如果我将字符串”ABCDEFG”赋值给ID型的变量,会怎么样呢?
如我们所料,会报异常,“ System.StringException: Invalid id: ABCDEFG ”。
这说明ID数据类型还是会对Id做合法性检查。
所以引出了最开始的问题,Salesforce是如何知道这个字符串是不是合法的ID的呢?
首先可以排除掉的可能性是Salesforce真的用这个字符串去数据库查一下。因为无论从性价比还是可行性上看,不会有哪个产品经理会同意这么做。
那么,既然Salesforce Id有文章开头提到的各种规则。
接来下比较容易想到的可能性是Salesforce使用了一套很复杂的规则来判断Id是否合法。
比如说
- 判断长度是否为15位到18位
- 判断头三位是不是已经存在的prefix
- 判断4到6位是否是本org的instance code
- 7到15位是否符合Id生成规则
- 16到18位是否符合前15位的计算结果
- 整体是否有非法字符
应该是一套足够严格的规则了。接下来,让我们做一组实验来一一验证。
首先在匿名块执行如下代码。
String test = '0016F000035LFXo'; // Replace with your org's record Id, valid one try{ Id myId = test; } catch(Exception e) { System.debug(e); } if(test instanceof id) { System.debug('Yes'); } else { System.debug('No'); }
不出所料,结果为没有异常,Yes。毕竟使用的是合法的Id。
接下来逐条验证。
1. 将test变量中的值,在最末加一个“1”,成为” 0016F000035LFXo1 “。执行匿名块。结果为有异常(System.StringException: Invalid id: 0016F000035LFXo1),No。 同样的,使用18位版本Id末尾加“1”,得到了相同的结果。确实有位数判断。
2. 将test变量中的值,头三位改成“ZZZ”,成为“ZZZ6F000035LFXo”。
结果为有异常(System.StringException: Invalid id: ZZZ6F000035LFXo),No。说明确实有prefix检查,但是我不服气的。每个org有哪些已经使用的prefix一定不一样,秉着Salesforce不可能去查表的原则,我确定挑战此规则。
2改.
将test变量中的值,头三位改成“0ZZ”,成为“0ZZ6F000035LFXo”。
结果为无异常,Yes。OK,说明检查的重点在第一位,我要找到它的边界,所以我坚持不懈的尝试,终于找到边界是小写的“z”,这样的话,第一位的范围是[0-9 a-z]。
3.
将test变量中的值,接着2改的结果,将4到6位改成“ZZZ”,成为“zZZZZZ00035LFXo”。 结果为有异常,No。 说明4到6位的检查也是存在的。接下来仍然本着不服的精神,进行了逐位的探索与尝试。
3改. 将4到6位中的第六位改回0,成为 “zZZZZ000035LFXo” 。结果无异常,Yes。根据尝试结果,第六位如果不是0都会报错。所以规则应该只是检查第六位是否为0。
4.
将test变量中的值,接着3改的结果,将7到15位改成“Z”,成为“zZZZZ0ZZZZZZZZZ”。 结果有异常,No。还是不服,继续挑战。
4改. 这次运气比较好,一次就试出来了。将第七位改回0,成为 “zZZZZ00ZZZZZZZZ”。结果无异常,Yes。根据尝试结果,第七位不是0都会报错。所以规则应该只是检查第七位是否为0.(与第六位一起是传说中的保留位?)
5. 将test变量中的值, 接着4改的结果,将所有大写Z换成$,成为“z$$$$00$$$$$$$$”, 结果无异常,Yes。说明没有字符数字以外字符的检查。
6. 将test变量中的值, 接着5的结果,在末尾加三个“$”,使之达到18位,成为“
z$$$$00$$$$$$$$$$$”,结果无异常,Yes。说明。。。后三位和前面也没有计算关系检查。
总结一下,Salesforce对Id的判定是根据如下规则:
1. 第一位必须是0-9, a-z
2. 第六位,第七位必须为0
3. 整体必须15位或者18位
所以 “z$$$$00$$$$$$$$$$$” 这样的Id虽然事实上不会存在,但在法理上是属于合法的Id。
另外还需要注意一点,SOQL检索的时候,由于真的可以去数据库验证,所以只有位数验证。意味着,用15个或者18个$,也是可以正常检索的,只不过永远找不到对应的数据而已。
此外,好奇心强的同学一定还想知道,既然$都算合法字符,那么空白字符算不算合法的?
比如“z 00 ”(z[4个空格]00[8个空格])。
OK,让我们来试一下,不出所料,结果无异常,Yes。。。(耸肩)
学到啦,真棒,谢谢老师。
老师,你确实很“变态” 🙂