Salesforce 中的數(shù)據(jù)庫(kù)操作方式
Salesforce 為用戶和開發(fā)者提供了四種基本的數(shù)據(jù)庫(kù)操作方式:
- Apex 中的 DML 語(yǔ)句
- Apex 中的 Database 類
- SOQL 查詢
- SOSL 查詢
DML 語(yǔ)句
DML 全稱 Data Manipulation Language膝擂,是 Apex 中直接進(jìn)行數(shù)據(jù)庫(kù)操作的一組命令弧可。和大多數(shù)數(shù)據(jù)庫(kù)類似,DML 語(yǔ)句包括:
- insert,插入
- update勘纯,更新
- upsert假瞬,插入或更新
- delete哥捕,刪除
- undelete诚纸,撤銷刪除
- merge,合并
每個(gè)DML語(yǔ)句都可以對(duì)一個(gè)或多個(gè) sObject 對(duì)象進(jìn)行操作谷炸。Salesforce 鼓勵(lì)用戶使用同一條 DML 語(yǔ)句對(duì)多條數(shù)據(jù)進(jìn)行操作北专,而不是對(duì)每條數(shù)據(jù)分別調(diào)用一次相同的 DML 語(yǔ)句。這樣做可以優(yōu)化執(zhí)行效率旬陡。
upsert 語(yǔ)句特點(diǎn)
upsert 語(yǔ)句包括了 insert 和 update 的功能拓颓。對(duì)于將要進(jìn)行 upsert 操作的數(shù)據(jù),Salesforce 會(huì)檢索數(shù)據(jù)庫(kù)中這些數(shù)據(jù)是否已經(jīng)存在描孟。對(duì)于已經(jīng)存在的數(shù)據(jù)驶睦,進(jìn)行 update 處理,對(duì)于不存在的數(shù)據(jù)画拾,進(jìn)行 insert 處理啥繁。
需要注意的是,upsert 語(yǔ)句的執(zhí)行效率比 update 和 insert 都要低青抛,所以我們?cè)谶M(jìn)行開發(fā)的時(shí)候,要盡可能的避免使用 upsert 語(yǔ)句酬核。
merge 語(yǔ)句特點(diǎn)
merge 語(yǔ)句可以將至多三條相同類型的記錄合并蜜另,只保留一條數(shù)據(jù),刪除其他兩條嫡意,并將之前與三條記錄相關(guān)的其他數(shù)據(jù)記錄重新關(guān)聯(lián)到保留的記錄中举瑰。
系統(tǒng)內(nèi)的 ID 字段
對(duì)于每個(gè)對(duì)象,無(wú)論是標(biāo)準(zhǔn)的還是自定義的蔬螟,Salesforce 都會(huì)自動(dòng)創(chuàng)建一個(gè) ID 字段此迅。該字段的值是由系統(tǒng)自動(dòng)生成,在整個(gè)系統(tǒng)內(nèi)部唯一存在,并且不會(huì)更改耸序。
在用戶利用 DML 的 insert 或 upsert 語(yǔ)句插入新的數(shù)據(jù)記錄后忍些,便可以直接使用該記錄的 ID 字段。
Account acc = new Account(Name='test account');
insert acc;
ID accountId = acc.Id;
在上面的代碼中坎怪,變量 accountId 中存儲(chǔ)了剛剛建立的 Account 記錄的 ID 值罢坝。用戶可以立即利用該 ID 值進(jìn)行其他操作。
DML 語(yǔ)句操作示例
// 插入單條數(shù)據(jù)
Account acc = new Account(Name='test');
insert acc;
// 插入多條數(shù)據(jù)
List<Account> accList = new List<Account> {
new Account(Name='test1'),
new Account(Name='test2'),
new Account(Name='test3'),
new Account(Name='test4')
};
insert accList;
// 更新單條數(shù)據(jù)
acc.Name = 'test name';
update acc;
// 更新多條數(shù)據(jù)
for(Account a : accList) {
a.Phone = '12345678';
}
update accList;
// 刪除單條數(shù)據(jù)
delete acc;
// 刪除多條數(shù)據(jù)
delete accList;
upsert 語(yǔ)句示例
upsert 語(yǔ)句運(yùn)行時(shí)搅窿,先比較數(shù)據(jù)中某個(gè)字段的值是否在數(shù)據(jù)庫(kù)中已經(jīng)存在嘁酿,如果存在則更新該數(shù)據(jù),否則插入該數(shù)據(jù)男应。
upsert 語(yǔ)句有兩個(gè)參數(shù)闹司,第一個(gè)參數(shù)是需要操作的單條數(shù)據(jù)或一組數(shù)據(jù),第二個(gè)參數(shù)是可選參數(shù)沐飘,表明了應(yīng)該用數(shù)據(jù)中的哪個(gè)字段進(jìn)行比較开仰,如果沒(méi)有聲明則默認(rèn)使用ID字段。
要注意的是薪铜,第二個(gè)參數(shù)必須是 ID 字段众弓、自定義的“外部 ID”字段或者索引字段。
假設(shè) Contact 對(duì)象中有一個(gè)“外部 ID”字段隔箍,名為“External_contact_person_number__c”谓娃,那么:
// 插入一條Contact數(shù)據(jù)
Contact con1 = new Contact(FirstName='A', LastName='LA');
insert con1;
// 插入數(shù)據(jù)之后更新數(shù)據(jù)
con1.Description = 'inserted contact 1';
// 新建另一條Contact數(shù)據(jù)
Contact con2 = new Contact(FirstName='B', LastName='LB');
// 將兩條Contact數(shù)據(jù)加入一個(gè)列表中
List<Contact> cons = new List<Contact> { con1, con2 };
// 對(duì)列表進(jìn)行upsert操作
upsert cons;
上面代碼執(zhí)行的結(jié)果是 con1 數(shù)據(jù)被更新了,con2 數(shù)據(jù)被插入了蜒滩。
如果上面的代碼改為:
Contact con1 = new Contact(FirstName='A', LastName='LA', External_contact_person_number__c = 'ex001');
insert con1;
Contact con2 = new Contact(FirstName='B', LastName='LB', External_contact_person_number__c = 'ex001');
upsert con2 Contact.Fields.External_contact_person_number__c;
那么系統(tǒng)在 upsert 時(shí)會(huì)比較 Contact 數(shù)據(jù)中的 External_contact_person_number__c 字段滨达,找到 External_contact_person_number__c 字段是 “ex001” 的數(shù)據(jù),然后直接進(jìn)行更新俯艰。所以上面代碼的執(zhí)行之后捡遍,系統(tǒng)中只有一條 Contact 記錄,其 FirstName 和 LastName 字段的值被更新為 “B”竹握。
注意画株,如果在 upsert 語(yǔ)句執(zhí)行時(shí),系統(tǒng)查找到系統(tǒng)中已經(jīng)有兩條或更多符合條件的記錄啦辐,則該操作會(huì)報(bào)錯(cuò)谓传,不會(huì)更新或插入任何數(shù)據(jù)。比如:
// 插入多條數(shù)據(jù)
List<Contact> conList = new List<Contact> {
new Contact(FirstName='A', LastName='LA', External_contact_person_number__c = 'ex001'),
new Contact(FirstName='B', LastName='LB', External_contact_person_number__c = 'ex001')
};
insert conList;
// 新建數(shù)據(jù)
Contact con = new Contact(FirstName='C', LastName='LC', External_contact_person_number__c = 'ex001');
// upsert新建的數(shù)據(jù)芹关,基于LastName字段
upsert con Contact.Fields.External_contact_person_number__c;
這段代碼會(huì)報(bào)錯(cuò)续挟,因?yàn)橄到y(tǒng)中已經(jīng)有了兩條 External_contact_person_number__c 為 “ex001” 的數(shù)據(jù),無(wú)法進(jìn)行插入或更新侥衬。
如果最后的 upsert 操作改為:
upsert con;
則不會(huì)有問(wèn)題双饥,因?yàn)楸容^的是 ID 字段,而 ID 字段必然是唯一的默穴,不存在于系統(tǒng)中,所以該記錄(con)會(huì)被插入博个。
Database 類
Apex中有Database類,其中包含了一組靜態(tài)函數(shù)际乘,它們的作用和 DML 語(yǔ)句類似:
- Database.insert()
- Database.update()
- Database.upsert()
- Database.delete()
- Database.undelete()
- Database.merge()
與 DML 語(yǔ)句不同的是坡倔,每個(gè)函數(shù)都有一個(gè)可選布爾型參數(shù),可以決定當(dāng)操作的一組數(shù)據(jù)中部分?jǐn)?shù)據(jù)出現(xiàn)錯(cuò)誤時(shí)脖含,是否將沒(méi)有出錯(cuò)的數(shù)據(jù)繼續(xù)執(zhí)行相應(yīng)的命令罪塔。
比如:
Database.insert(accList, false);
如果插入的一組數(shù)據(jù) accList 中有不符合條件的數(shù)據(jù),那么系統(tǒng)會(huì)跳過(guò)這些數(shù)據(jù)养葵,將剩下的數(shù)據(jù)成功插入數(shù)據(jù)庫(kù)征堪,并且不會(huì)報(bào)錯(cuò)。
該布爾型參數(shù)默認(rèn)為“真”(true)关拒。當(dāng)有部分?jǐn)?shù)據(jù)出錯(cuò)時(shí)佃蚜,所有數(shù)據(jù)都不會(huì)被執(zhí)行相應(yīng)的操作,并報(bào)錯(cuò)着绊。
Database 類的操作返回值
Database 類的操作函數(shù)會(huì)返回一組值谐算,對(duì)于進(jìn)行操作的每一條數(shù)據(jù),都會(huì)有成功或失敗的信息归露。
// insert 的結(jié)果
Database.SaveResult[] = Database.insert(recordList, false);
// upsert 的結(jié)果
Database.UpsertResult[] = Database.upsert(recordList, false);
// delete 的結(jié)果
Database.DeleteResult[] = Database.delete(recordList, false);
SOQL
SOQL 是 Salesforce 提供的數(shù)據(jù)庫(kù)操作語(yǔ)言洲脂,全稱是 Salesforce Object Query Language,類似于 SQL剧包。
在 Developer Console 的 Query Editor 部分恐锦,可以鍵入 SOQL 語(yǔ)句并進(jìn)行查詢。
在 Apex 中疆液,可以直接調(diào)用 SOQL 語(yǔ)句操作一個(gè)或一組 sObject 對(duì)象一铅。
比如:
List<Account> accList = [SELECT Name FROM Account];
SOQL 語(yǔ)法
SOQL 基本語(yǔ)法和 SQL 類似,比如 SELECT 語(yǔ)句的格式是:
SELECT 字段 FROM sObject [WHERE 條件]
其中 WHERE 語(yǔ)句是可選部分堕油。
要注意的是:
- SELECT 后面聲明的字段需要用逗號(hào)隔開潘飘,并且不能用“*”來(lái)選取所有字段,必須聲明每個(gè)要查詢的字段
- 對(duì)于不存在于 SELECT 語(yǔ)句的字段馍迄,系統(tǒng)不會(huì)去查詢其值福也,所以后面的語(yǔ)句無(wú)法使用這些字段的值
比如:
List<Account> accList = [SELECT Id, Name FROM Account];
// 使用 Phone 字段會(huì)出錯(cuò)
// accList[0].Phone = '12345678';
查詢結(jié)果中的每個(gè) Account 對(duì)象只包含 Id 和 Name 字段的值,如果用戶想使用 Phone 字段的值攀圈,系統(tǒng)會(huì)報(bào)錯(cuò)。
SELECT 語(yǔ)句后面也可以加 ORDER BY 和 LIMIT 語(yǔ)句峦甩。比如:
List<Account> accList = [SELECT Id, Name FROM Account ORDER BY Name LIMIT 20];
通配符
在 SOQL 的 WHERE 語(yǔ)句中赘来,如果想查詢某字段包含某個(gè)值的話现喳,可以用通配符進(jìn)行模糊查詢。比如:
SELECT Id, Name FROM Account WHERE Name LIKE '%test%'
上面的語(yǔ)句查詢的是字段 Name 中包含 “test” 的所有 Account 記錄犬辰。
使用變量
如果要在 SOQL 查詢中使用變量嗦篱,則變量名前需要用“:”來(lái)引導(dǎo)。比如:
String queryStr = 'test';
List<Account> accList = [SELECT Id, Name FROM Account WHERE Name LIKE :queryStr];
關(guān)聯(lián)對(duì)象的查詢
在 SOQL 語(yǔ)句中幌缝,可以嵌套查詢相關(guān)聯(lián)的對(duì)象灸促。在子對(duì)象中,定義了和父對(duì)象相關(guān)聯(lián)的字段涵卵,其中的“子級(jí)關(guān)系名稱”屬性需要在查詢中使用浴栽。
對(duì)于標(biāo)準(zhǔn)對(duì)象,“子級(jí)關(guān)系名稱”可以直接使用轿偎。對(duì)于自定義對(duì)象典鸡,要在“子級(jí)關(guān)系名稱”后面加上“__r”。
比如:
// 嵌套查詢和 Account 相關(guān)的 Contact 對(duì)象坏晦,其中 “Contacts” 是 Contact 對(duì)象中和父對(duì)象 Account 關(guān)系字段的子級(jí)關(guān)系名稱
List<Account> accWithConList = [SELECT Name,
(SELECT FirstName, LastName FROM Contacts)
FROM Account
WHERE Name like '%test'
];
// 查詢到的 Contact 對(duì)象
List<Contact> firstConList = accWithConList[0].Contacts;
// 使用 Contact 對(duì)象中查詢到的值
String firstNameFromQuery = firstConList[0].FirstName;
String lastNameFromQuery = firstConList[0].LastName;
又如:
// 查詢父對(duì)象的字段內(nèi)容
List<Contact> conList = [SELECT Account.Name FROM Contact WHERE FirstName = 'testFirst'];
// 使用父對(duì)象的字段內(nèi)容
String accName = conList[0].Account.Name;
自定義對(duì)象的關(guān)聯(lián)對(duì)象
比如:
- 在系統(tǒng)中建立了 “Address__c” 對(duì)象和 “Street__c” 對(duì)象
- 每個(gè) “Address__c” 對(duì)象中包含若干個(gè) “Street__c” 對(duì)象
- 在 “Street__c” 對(duì)象中定義了字段表明和 “Address__c”的關(guān)系萝玷,其“子級(jí)關(guān)系名稱”的名字是 “Streets”。那么查詢可以這樣寫:
// 從父對(duì)象查詢子對(duì)象的字段
SELECT Name, (SELECT Name FROM Streets__r) FROM Address__c
// 從子對(duì)象查詢父對(duì)象的字段
SELECT Name, Address__r.Name FROM Street__c
SOSL
SOSL 是 Salesforce 提供的數(shù)據(jù)庫(kù)操作語(yǔ)言昆婿,全稱是 Salesforce Object Search Language球碉。
SOSL 主要用于在數(shù)據(jù)庫(kù)的各個(gè)對(duì)象中查詢符合條件的列。
SOSL 和 SOQL 類似仓蛆,都可以在 Apex 中直接調(diào)用睁冬。SOSL 返回的類型永遠(yuǎn)是一個(gè)包含了 sObject 對(duì)象列表的列表,即 List<List<SObject>> 類型多律。
比如痴突,對(duì)于所有 Account 和 Contact 對(duì)象,查詢?nèi)我蛔侄沃邪?“test” 的記錄:
List<List<SObject>> resultList = [FIND 'test'
IN ALL FIELDS
RETURNING Account(Name), Contact(FirstName, LastName)];
返回的結(jié)果便是符合條件的兩個(gè)列表狼荞,一個(gè)列表包含 Account 對(duì)象辽装,其中只有 Name 的值,另一個(gè)列表包含 Contact 對(duì)象相味,其中只有 FirstName 和 LastName 的值拾积。
SOSL語(yǔ)法
SOSL 的基本語(yǔ)法是:
FIND 要查詢的字符串 IN 要查找的字段 RETURNING 查詢結(jié)果包含的對(duì)象和字段名
其中:
- 要查詢的字符串是無(wú)關(guān)大小寫的
- 要查找的字段是可選參數(shù),默認(rèn)是所有字段丰涉,即 “ALL FIELDS”拓巧,也可以在此聲明只在某幾個(gè)字段中查詢,可以使用的僅限于:“NAME FIELDS”一死、“EMAIL FIELDS”肛度、“PHONE FIELDS”、“SIDEBAR FIELDS”
- 查詢結(jié)果包含的對(duì)象和字段名可以包含一個(gè)或多個(gè)想要查詢的對(duì)象投慈,并聲明哪些字段保存在查詢結(jié)果中