【问题标题】:Need help in Dynamic SOQL在动态 SOQL 方面需要帮助
【发布时间】:2021-06-18 16:02:05
【问题描述】:

在我的代码中,我需要从记录 id 中获取对象名称,并且基于对象名称,我需要获取字段名称以添加到我的查询中。现在,我已经硬编码了字段名称,有没有更好的方法来做到这一点。 where 子句中的字段是lease__c 对象中的查找字段。

public List<SObject> getObjectData(String recordId) {
        String sObjName = Id.valueOf(recordId).getSObjectType().getDescribe().getName();
       String fieldName = '';
        if (sObjName == 'Property__c') {
            fieldName = 'Property__c';
        }
        else if (sObjName == 'Account') {
                 fieldName = 'Account__c';
        }
        string query = 'SELECT Id, Greatest_MRI_Vacate_Date__c FROM Lease__c WHERE' + fieldName + '=: recordId';
}

【问题讨论】:

    标签: salesforce apex soql


    【解决方案1】:

    哦,有趣的一个!

    首先,您会考虑反转查询吗?如果您可以“承诺”相关的租约列表始终具有相同的 API 名称,您可以这样做

    SELECT Id, 
        (SELECT Greatest_MRI_Vacate_Date__c FROM Leases__r)
    FROM Account
    WHERE Id = :recordId
    
    SELECT Id, 
        (SELECT Greatest_MRI_Vacate_Date__c FROM Leases__r)
    FROM Property__c
    WHERE Id = :recordId
    

    看起来有点简单?

    然后您可以使用result[0].getSobject('Leases__r')[0].get('Greatest_MRI_Vacate_Date__c') 浏览相关列表。

    如果没有 - 这应该是您需要的良好开端。这有点危险(嗯,危险......不是通用的)。因为如果您有 2 次查找帐户怎么办?或者如果您遇到像OwnerId 这样的“突变字段”可以是用户或队列怎么办。在Task.WhatId 上可以指向几十个表。等等。

    for(Schema.SObjectField sf : Contact.sObjectType.getDescribe().fields.getMap().values()){
        Schema.DescribeFieldResult dfr = sf.getDescribe();
        if(dfr.getType() == DisplayType.REFERENCE){
            System.debug(sf + ' is a lookup to ' + dfr.getReferenceTo());
        }
    }
    MasterRecordId is a lookup to (Contact)
    AccountId is a lookup to (Account)
    RecordTypeId is a lookup to (RecordType)
    ReportsToId is a lookup to (Contact)
    OwnerId is a lookup to (User)
    CreatedById is a lookup to (User)
    LastModifiedById is a lookup to (User)
    IndividualId is a lookup to (Individual)
    

    getReferenceTo() 返回标记列表(如 Id.getSobjectType() 返回标记,您可以按原样比较它们,而无需转换为字符串或调用额外的描述)。大多数情况下,列表中只有 1 个。 OwnerIdTask.WhoId, WhatId 是一些极端情况。

    有了这个循环,你也可以说全部搞砸,我要全部尝试,看看有什么效果。性能可能马马虎虎。从理论上讲,它们是查找,因此索引...您需要进行实验。

    SELECT Id FROM Contact WHERE MasterRecordId = :i OR AccountId = :i OR RecordTypeId = :i OR ...
    

    【讨论】:

      【解决方案2】:

      请问您为什么要这样做?
      我问是因为可能有一种更清洁的方法来实现您想要做的事情。
      多态性旨在减少使用此类 if 语句的代码。

      你考虑过这样的事情吗?

      1. 构建一个简单的抽象类
      public abstract Lease {
          public Id recordId { get; private set; }
      
          public Lease(Id recordId) {
              this.recordId = recordId;
          }
      
          public Date getGreatestMRIVacateDate() {
              return Database.Query( getHighestQuery() )
          }
      
          private String getHighestQuery() {
              return 'SELECT 
                          Id, 
                          Greatest_MRI_Vacate_Date__c
                      FROM Lease__c
                      WHERE ' + getObjectIdField() + ' =:recordId';
          }
      
          protected abstract String getObjectIdField();
      }
      
      1. 为您的用例扩展类
      public Property extends Lease {
          public Property(Id recordId) {
              super(recordId);
          }
      
          private override String getObjectIdField() {
              return 'Property__c';
          }
      }
      
      public Account extends Lease {
          public Account(Id recordId) {
              super(recordId);
          }
          private override String getObjectIdField() {
              return 'Account__c';
          }
      }
      
      1. 创建工厂类
      public class LeaseFactory {
          public class TypeException extends Exception();
      
          public static Lease getLease(Id recordId) {
              String objType = getSObjectType(recordId);
              switch on objType {
                  when 'Property__c' {
                      return new Property(recordId);
                  }
                  when 'Account__c' {
                      return new Account(recordId);
                  }
                  when else {
                      throw new TypeException('Unknown Type: ' + recordId);
                  }
              }
          }
      
          private static String getSObjectType(Id recordId) {
              return Id.valueOf(recordId).getSObjectType().getDescribe().getName();
          }
      }
      
      1. 现在您可以在代码中动态而干净地使用它
          List<Id> recordIds;
          for (Id recordId : recordIds) {
              Lease l = LeaseFactory.getLease(recordId);
              System.debug( l.getGreatestMRIVacateDate() );
          }
      

      这可能看起来设计过度(并且可能有一种方法可以使它更简洁),但这种方法的优点是,如果您决定添加更多功能,例如 getLowestMRIVacateDate,您只需要一次编辑代码地点:租赁类。然后,该功能将过滤到您的其余类。

      这减少了您必须执行该 if 语句的次数,该语句确定它是哪种类型,而不是潜在地必须在每个方法中执行它。从长远来看,它使代码更简洁、更短且更易于遵循。

      请注意,我很确定还有一种更简洁的方式仍在使用界面,但我很累,现在不想弄清楚。我建议看这个: https://www.youtube.com/watch?v=NU_1StN5Tkk

      另一方面,如果您只有这种方法,您是否考虑过 SOSL 而不是 SOQL? 我不是很精通它,但我相信您可以按照以下方式做一些事情:

      FIND :recordId IN (Account__c, Property__c) RETURNING Lease(Id, Greatest_MRI_Vacate_Date__c)
      

      见:https://developer.salesforce.com/docs/atlas.en-us.soql_sosl.meta/soql_sosl/sforce_api_calls_sosl_find.htm

      【讨论】:

      • 谢谢布赖恩!很有帮助。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-27
      • 2014-02-06
      • 2017-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多