salesforce零基礎學習(七十一)級聯表DML操作


曾經做項目沒有考慮那么多,對於級聯表操作都是正常的一步一步操作,沒有考慮過失敗情況,最近項目遇見了失敗的情況,導致碰到了相應的情況,特此mark一下,免得后期繼續踩坑。

需求如下:新建頁面,頁面中包含1.新建企業,2.新建聯系人,3.新建機會。任何一步的邏輯或者DML操作失敗都會導致整體的回滾。只有當三步都正常插入成功了以后才會跳轉到新生成的機會的標准頁面。

1.NewOpportunityController:這里做了一個邏輯判斷,當聯系人為空情況下,不允許新建聯系人。當然,現實場景不會在這里判斷,但是現實場景會有很多的復雜的業務邏輯,這里只是簡單的處理。

 1 public class newOpportunityController { 
 2     Account account; 
 3     Contact contact; 
 4     Opportunity opportunity; 
 5     OpportunityContactRole role;
 6     
 7     public Account getAccount() { 
 8         if(account == null) 
 9             account = new Account(); 
10         return account; 
11     } 
12     public Contact getContact() { 
13         if(contact == null) 
14             contact = new Contact(); 
15         return contact; 
16     } 
17     public Opportunity getOpportunity() { 
18         if(opportunity == null) 
19             opportunity = new Opportunity(); 
20         return opportunity; 
21     }
22     public OpportunityContactRole getRole() { 
23         if(role == null) 
24             role = new OpportunityContactRole(); 
25         return role; 
26     }
27 
28     
29     public PageReference save() { 
30         Savepoint sp = Database.setSavepoint();
31         try {
32             account.phone = contact.phone; 
33             insert account; 
34         } catch(Exception e) {
35             Database.rollback(sp);
36             ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'插入企業失敗'));
37 
38             return null;
39         }   
40         try {
41             if(contact.phone == null) {
42                 Database.rollback(sp);
43                 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'聯系人電話不能為空'));
44                 return null;
45             }
46             contact.accountId = account.id; 
47             insert contact; 
48         } catch(Exception e) {
49             Database.rollback(sp);
50             ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'插入聯系人失敗'));
51             return null;
52         }
53         try {
54             opportunity.accountId = account.id; 
55             insert opportunity; 
56             role.opportunityId = opportunity.id; 
57             role.contactId = contact.id; 
58             insert role; 
59         } catch(Exception e) {
60             Database.rollback(sp);
61             ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'插入機會失敗'));
62             return null;
63         }
64         //跳轉到新插入的opportunity的系統頁面
65         PageReference opptyPage = new ApexPages.StandardController(opportunity).view(); 
66         opptyPage.setRedirect(true); 
67         return opptyPage;
68     }
69 }

2.NewOpportunityPage:填寫企業信息,聯系人信息和機會信息並實現提交

 1 <apex:page controller="newOpportunityController" tabStyle="Opportunity"> 
 2     
 3     <apex:sectionHeader title="New Customer Opportunity"/> 
 4     <apex:form id="theForm"> 
 5         <apex:pageMessages/>
 6         <apex:pageBlock title="Customer Information" mode="edit"> 
 7             <apex:pageBlockSection title="Account Information"> 
 8                 <apex:inputField id="accountName" value="{!account.name}"/> 
 9                 <apex:inputField id="accountSite" value="{!account.site}"/> 
10             </apex:pageBlockSection> 
11             <apex:pageBlockSection title="Contact Information"> 
12                 <apex:inputField id="contactFirstName" value="{!contact.firstName}"/> 
13                 <apex:inputField id="contactLastName" value="{!contact.lastName}"/> 
14                 <apex:inputField id="contactPhone" value="{!contact.phone}"/> 
15             </apex:pageBlockSection> 
16 
17             <apex:pageBlockSection title="Opportunity Information"> 
18                 <apex:inputField id="opportunityName" value="{!opportunity.name}"/> 
19                 <apex:inputField id="opportunityAmount" value="{!opportunity.amount}"/> 
20                 <apex:inputField id="opportunityCloseDate" value="{!opportunity.closeDate}"/> 
21                 <apex:inputField id="opportunityStageName" value="{!opportunity.stageName}"/> 
22                 <apex:inputField id="contactRole" value="{!role.role}"/> 
23             </apex:pageBlockSection> 
24 
25             <apex:pageBlockButtons > 
26                 <apex:commandButton action="{!save}" value="Save" reRender="theForm"/> 
27             </apex:pageBlockButtons>
28 
29         </apex:pageBlock> 
30 
31     </apex:form> 
32 </apex:page>

效果展示: 

1.填寫相關信息,提交表單,特意沒有輸入聯系人,顯示效果如下:

2.當對數據進行相關填充以后,結果如下:

再次保存以后提示不能對於已經有ID的對象執行insert操作的錯誤信息。當時沒有太理解因為什么原因導致了這種情況,后來joe給我答疑解惑,我才如夢初醒。當我對Account表執行了insert時,在事務還沒有commit情況下,此條記錄還沒有存儲到數據庫中,但是controller中的對象便已經有了ID字段的值。當后期操作需要事務回滾時,數據庫不保存insert進去的記錄,但是此對象的ID卻不會被清空,這就導致了下次insert此對象時,此對象已經有了ID,從而不能進行insert的操作了。同理,如果數據庫沒有當前的數據,對象卻有ID,即使執行upsert操作也是會報類似的錯誤。

在我們對相關級聯表進行DML操作的時候,可以使用clone操作,當回滾的時候,只是回滾數據庫的內容,但是原來綁定到前台的對象並沒有生成相關的ID,從而可以擺脫上述的尷尬。對Controller層改造代碼如下:

 1 public class newOpportunityController { 
 2     Account account; 
 3     Contact contact; 
 4     Opportunity opportunity; 
 5     OpportunityContactRole role;
 6     
 7     public Account getAccount() { 
 8         if(account == null) 
 9             account = new Account(); 
10         return account; 
11     } 
12     public Contact getContact() { 
13         if(contact == null) 
14             contact = new Contact(); 
15         return contact; 
16     } 
17     public Opportunity getOpportunity() { 
18         if(opportunity == null) 
19             opportunity = new Opportunity(); 
20         return opportunity; 
21     }
22     public OpportunityContactRole getRole() { 
23         if(role == null) 
24             role = new OpportunityContactRole(); 
25         return role; 
26     }
27 
28     public PageReference save() { 
29         Savepoint sp = Database.setSavepoint();
30         Account cloneAccount;
31         Contact cloneContact;
32         Opportunity cloneOpportunity;
33         OpportunityContactRole cloneRole;
34         try {
35             account.phone = contact.phone; 
36             cloneAccount = account.clone(true);
37             insert cloneAccount; 
38         } catch(Exception e) {
39             Database.rollback(sp);
40             ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'插入企業失敗'));
41 
42             return null;
43         }   
44         try {
45             if(contact.phone == null) {
46                 Database.rollback(sp);
47                 ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'聯系人電話不能為空'));
48                 return null;
49             }
50             contact.accountId = cloneAccount.Id; 
51             cloneContact = contact.clone(true);
52             insert cloneContact; 
53         } catch(Exception e) {
54             Database.rollback(sp);
55             ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'插入聯系人失敗'));
56             return null;
57         }
58         try {
59             opportunity.accountId = cloneAccount.id; 
60             cloneOpportunity = opportunity.clone(false);
61             insert cloneOpportunity; 
62             role.opportunityId = cloneOpportunity.id; 
63             role.contactId = cloneContact.id; 
64             cloneRole = role.clone(false);
65             insert cloneRole; 
66         } catch(Exception e) {
67             Database.rollback(sp);
68             ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'插入機會失敗'));
69             return null;
70         }
71         //跳轉到新插入的opportunity的系統頁面
72         PageReference opptyPage = new ApexPages.StandardController(cloneOpportunity).view(); 
73         opptyPage.setRedirect(true); 
74         return opptyPage;
75     }
76 }

效果展示:

1.當信息填寫不完整情況下效果展示:

 2.填好信息保存以后跳轉到標准頁面

 總結:當對級聯表進行操作的時候,一定要考慮一下當因為某些業務邏輯或者數據自身操作失敗導致需要回滾情況下,導致數據庫中不存在本條記錄然而后台綁定的對象卻相關復制的情況,如果編輯的case沒有問題,但是涉及到新增的情況便暴露出來此問題了。篇中有描述錯誤的地方歡迎指出,有不懂得歡迎留言。除了使用clone操作以外應該還有其他的好操作可以避免此種事情的發生,如果有更好的操作,歡迎留言。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM