0

I have a visualforce page on the work order object with a form that is getting filled out. The form lists out all of the assets on an order. A user is able to fill out information for each asset, click the save button, and all of the info is saved to the asset record. Each asset also has a related case. I am trying to enter in the install date for each asset and have that value save to the install date field on the related ticket. I was able to query the install date field from the related ticket and put it on the visualforce page, but when I click the save button it doesn't save the value of the install date field on the related ticket. I have also tried putting the install date field from the asset on the visualforce page, enter in the install date on the asset, then when the save button is click the install date value is saved to the asset and pushes to the install date field on the related ticket. When I try this I get an error that says

"SObject row was retrieved via SOQL without querying the requested field: Asset.New_Equipment_Setup_and_Install_Ticket__r Error is in expression '{!saveSerialIdNumber}' in component apex:commandButton in page installupdateassetworkorder: Class.installUpdateAssetWorkOrderClass.saveSerialIdNumber: line 59, column 1."

Here is my visualforce page for the form that is being filled out:

   <apex:page docType="html-5.0" standardController="WorkOrder" extensions="installUpdateAssetWorkOrderClass" id="thePage">     
   
   <apex:form id="theForm"> 
       
        <apex:pageblock id="Assets">
            
                <apex:pageBlockTable rows="" id="pbt0" value="{!WorkOrder.Assets__r}" var="asset">
            
                <apex:column headerClass="textAlignCenter" rendered="{!asset.SBQQ__RequiredByAsset__c == null}" style="width:16.66666666666667%;" headerValue="Product Code"><!-- to take the label dynamically -->
                    <apex:inputText style="width:94%;" disabled="true" styleClass="setupModelForId" value="{!asset.Product_Code_for_Paperless_Install_Docs__c}"></apex:inputText>
                </apex:column>
            
                
                
                <apex:column headerClass="textAlignCenter" rendered="{!asset.SBQQ__RequiredByAsset__c == null}" style="width:20%;" headerValue="ID Number"><!-- to take the label dynamically -->
                    <apex:inputText style="width:94%;" styleClass="idNumber" value="{!asset.New_Asset_Install_LOC_ID_Number__c}">
                        <apex:actionSupport event="onchange" action="{!updateIdNumber}"/>
                    </apex:inputText>
                </apex:column>
                
                    
                    
                <apex:column headerClass="textAlignCenter" rendered="{!asset.SBQQ__RequiredByAsset__c == null}" style="width:16.66666666666667%;" headerValue="B/W Meter"><!-- to take the label dynamically -->
                    <apex:inputText required="true" styleClass="bwMeter" style="width:94%;" value="{!asset.New_Asset_Install_B_W_Meter__c}"  />
                </apex:column>
                
                <apex:column headerClass="textAlignCenter" rendered="{!asset.SBQQ__RequiredByAsset__c == null}" style="width:16.66666666666667%;" headerValue="Color Meter"><!-- to take the label dynamically -->
                    <apex:inputText styleClass="colorMeter" style="width:94%;" value="{!asset.New_Asset_Install_Color_Meter__c}"  />
                </apex:column>
                
                <apex:column headerClass="textAlignCenter" rendered="{!asset.SBQQ__RequiredByAsset__c == null}" style="width:16.66666666666667%;" headerValue="I.P. Address"><!-- to take the label dynamically -->
                    <apex:inputText styleClass="ipAddress" style="width:94%;" value="{!asset.New_Asset_Install_Equipment_IP_Address__c}"  />
                </apex:column>
                
                <apex:column headerClass="textAlignCenter" style="width:16.66666666666667%;" rendered="{!asset.SBQQ__RequiredByAsset__c == null}" headerValue="Install Date">
                    <apex:inputField id="installDate" styleClass="installDate" value="{!asset.Install_Date__c}"/>
                </apex:column>
                
                <apex:column headerClass="textAlignCenter" style="width:16.66666666666667%;"  headerValue="Install Date">
                    <apex:outputText value="{!asset.New_Equipment_Setup_and_Install_Ticket__r.Install_Date__c}" rendered="false"/>
                 </apex:column>
                    
                 <apex:column headerClass="textAlignCenter" style="width:16.66666666666667%;" rendered="{!asset.SBQQ__RequiredByAsset__c == null}" styleClass="" headerValue=""><!-- to take the label dynamically -->
                        <apex:inputText disabled="true" style="" styleClass="setupIdNumber" value="{!asset.New_Asset_Setup_LOC_ID__c}"  />
                 </apex:column>
                    
                    
            
            </apex:pageBlockTable>
            
       </apex:pageblock>
       
    </apex:form>
    
</apex:page>

Here is my apex class with the save button:

public class installUpdateAssetWorkOrderClass {

private ApexPages.StandardController controller;

public List<WorkOrderLineItem> WorkOrderLineItems{get;set;}

public List<WorkOrderLineItem> WorkOrderLineItemsSupplies{get;set;}

public List<Asset> Assets{get;set;}

public List<Case> Cases{get;set;}

public WorkOrder WorkOrders {get;set;} 

public WorkOrder wo {get;set;} 

 

//Constructor 

 public installUpdateAssetWorkOrderClass(ApexPages.StandardController controller) {
    this.controller = controller;
     


    wo = (WorkOrder)controller.getRecord();      
     
    WorkOrders = [SELECT id FROM WorkOrder WHERE id=: wo.id LIMIT 1];  

    Assets = [SELECT id, Install_Date__c, New_Equipment_Setup_and_Install_Ticket__r.Install_Date__c, Product2.Serialized__c, New_Equipment_Setup_and_Install_Ticket__c, Show_in_MultiMachine_Delivery_Acceptance__c,SerialNumber,Name,Delivery_Address__c,Product_Code_Display__c,Product_Description_Display__c FROM Asset where Work_Order__c = :WorkOrders.id]; 
 
    Cases = [SELECT id, AssetId,Asset.Name,Install_Date__c, Cheater_Left_On_Sight__c FROM Case WHERE Work_Order__c = : WorkOrders.id];
 
 } 

//update ID number
public void updateIdNumber(){
    for(Asset assetObj : (list<Asset>) ((WorkOrder) controller.getRecord()).Assets__r){
       if(assetObj.SBQQ__RequiredByAsset__c == null){
        assetObj.Name = assetObj.New_Asset_Install_LOC_ID_Number__c;
        } 
    } 
    update ((WorkOrder) controller.getRecord()).Assets__r;
    
}

public void saveSerialIdNumber() {
    
    for(Asset assetObj : (list<Asset>) ((WorkOrder) controller.getRecord()).Assets__r){
        
        assetObj.SerialNumber = assetObj.New_Asset_Install_LOC_Serial_Number__c;
        
        assetObj.New_Equipment_Setup_and_Install_Ticket__r.Install_Date__c = assetObj.Install_Date__c;
         
    }
   
    
    update ((WorkOrder) controller.getRecord()).Assets__r;
    
    controller.save();
    
    
}

 

}

Any help would be greatly appreciated. Thanks!

1 Answer 1

0

Assuming line 59 is this line:

assetObj.New_Equipment_Setup_and_Install_Ticket__r.Install_Date__c = assetObj.Install_Date__c;

Then the issue is that the relationship object New_Equipment_Setup_and_Install_Ticket__r doesn't exist in the controller's object state. This leads us to how assetObj is defined

for(Asset assetObj : (list<Asset>) ((WorkOrder) controller.getRecord()).Assets__r){

and in turn, this leads us to the controller.getRecord().

In VF, the object returned by getRecord() will only include fields that have explicit VF page markup (i.e. an apex:inputField, apex:outputField, apex:variable, etc). Your form only references via VF components fields on Asset.

This is all described here in the VF Doc

Note that only the fields that are referenced in the associated Visualforce markup are available for querying on this SObject. All other fields, including fields from any related objects, must be queried using a SOQL expression.

Tip You can work around this restriction by including a hidden component that references any additional fields that you want to query. Hide the component from display by setting the component's rendered attribute to false.

So, either re-query for the related record in the controller or use the hidden field approach.

5
  • In my visualforce page I added the field that I am trying to save the value to as a hidden field. Here is the value I am inputing: <apex:inputField id="installDate" styleClass="installDate" value="{!asset.Install_Date__c}"/> This is the hidden field I want to save it to: <apex:outputText value="{!asset.New_Equipment_Setup_and_Install_Ticket__r.Install_Date__c}" rendered="false"/> Doing this I get an "Attempt to de-reference a null object" error on line 61 column one of my class: assetObj.New_Equipment_Setup_and_Install_Ticket__r.Install_Date__c = assetObj.Install_Date__c;
    – Ian
    Sep 30, 2020 at 14:56
  • @Ian - Please edit your original post with the changes in the comment and I'll take another look - it is too hard for me to know the current state of your code from the above comment
    – cropredy
    Oct 1, 2020 at 3:37
  • @croprdy thank you, I went ahead and updated my original post
    – Ian
    Oct 5, 2020 at 17:07
  • hmm - that should have worked; instead of binding to the getRecord()'s related list of assets; bind the VF markup to wo and change the constructor to requery Workorder and children in a single SOQL; then do update on wo.Assets__r in your action methods
    – cropredy
    Oct 6, 2020 at 19:19
  • I'm sorry I'm not sure I understand what you are asking me to try
    – Ian
    Oct 8, 2020 at 15:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .