Apex 中的 DataWeave - 动态指定 SObject 类

问题描述 投票:0回答:1

我有一个运行良好的 DataWeave 脚本。我在 Apex 类中使用它。再次,效果很好。这是它:

%dw 2.0
input csvData application/csv
input fieldMappings application/json
input objectProperties application/json
var objectName = objectProperties.ObjectName


output application/apex
---

csvData map ((row) ->
    (
        (
        fieldMappings map (fieldMapping) ->
        (fieldMapping.target) : if(row[fieldMapping.source] != "") row[fieldMapping.source] else fieldMapping."defaultValue"
        )
        reduce ($$ ++ $)
    ) as Object {class: "Requirement__c"}
)

csvData 看起来像:

First Name,Last Name,Title,Height,Color
Jane, Austin, CEO,7,blue
Bob, Smith, COO, 6,red

fieldMappings 看起来像:

[
  {
    "source": "First Name",
    "target": "FirstName"
  },
  {
    "source": "Last Name",
    "target": "LastName"
  },
  {
    "source": "Title",
    "target": "Title"
  },
  {
    "source": "Height",
    "target": "Height__c"
  },
  {
    "source": "Importance",
    "target": "Priority__c"
  },
  {
    "source": "Interests",
    "target": "Hobbies__c"
  }
]

我没有在上面的代码中使用objectProperties,但下面我确实使用了它,它看起来像

{
    "ObjectName":"Contact"
}

但我真正想要的是对象类是动态的,如下所示 - 请注意,我用 DataWeave 变量替换了“Requirement__c”。问题是,DataWeave 按字面意思获取世界对象名称...并且我收到错误。我没有复制错误,并且对代码进行了太多更改,我不记得了,但基本上错误类似于“它无法转换 csvData map ((row) -> ... class : objectName”

它似乎忽略了变量 objectName 并将其视为字符串文字

%dw 2.0
input csvData application/csv
input fieldMappings application/json
input objectProperties application/json
var objectName = objectProperties.ObjectName


output application/apex
---

csvData map ((row) ->
    (
        (
        fieldMappings map (fieldMapping) ->
        (fieldMapping.target) : if(row[fieldMapping.source] != "") row[fieldMapping.source] else fieldMapping."defaultValue"
        )
        reduce ($$ ++ $)
    ) as Object {class: objectName}
)

有什么想法吗?

salesforce dataweave
1个回答
0
投票

好吧,所以我放弃了尝试动态使用

as Object {class: objectProperties.ObjectName}

DataWeave 脚本内部

相反,我决定既然我们可以序列化和反序列化 SObject,我就让 Apex 代码处理对象方面。

首先我简单地尝试了

List<SObject> objectList = (List<SObject>)JSON.deserialize(jsonText,List<SObject>.class);

但问题是我收到了有关多态对象的错误。这是因为 DataWeave 的输出如下所示:

[
  {        
    "FirstName": "Jane",
    "LastName": " Austin",
    "Title": " CEO",
    "Height__c": "7",
    "Priority__c": null,
    "Hobbies__c": null
  },
  {        
    "FirstName": "Bob",
    "LastName": " Smith",
    "Title": " COO",
    "Height__c": " 6",
    "Priority__c": null,
    "Hobbies__c": null
  }
]

Salesforce 需要 JSON 中的附加属性来确定 SObject 的类型。 Salesforce 希望 JSON 看起来像:

[
  {
    "attributes": {
      "type": "Contact"
    },
    "FirstName": "Jane",
    "LastName": " Austin",
    "Title": " CEO",
    "Height__c": "7",
    "Priority__c": null,
    "Hobbies__c": null
  },
  {
    "attributes": {
      "type": "Contact"
    },
    "FirstName": "Bob",
    "LastName": " Smith",
    "Title": " COO",
    "Height__c": " 6",
    "Priority__c": null,
    "Hobbies__c": null
  }
]

注意对象名称位于“类型”之后

这就是我所做的。我修改了 DataWeave 脚本以简单地输出 JSON(忘记输出应用程序/apex)

%dw 2.0

input csvData application/csv
input fieldMappings application/json
input objectProperties application/json

var applyMapping = (in, mappings) -> (
   mappings map (fieldMapping) -> {
    (fieldMapping.target) : if(in[fieldMapping.source] != "") in[fieldMapping.source] else fieldMapping."defaultValue"
  }
)

var reduceThis = (in) -> (
    in
    reduce ($$ ++ $) 
)

var attributeThis = (in) -> (
    {
        attributes: {
            "type" : objectProperties.ObjectName
        }
    } ++ in
)

output application/json
---

csvData map ((row) -> 
    (        
        attributeThis(reduceThis(applyMapping(row,fieldMappings)))     
    )
)

这将读取 CSV 的每一行。 它将动态地从 fieldMappings 找出如何将 CSV 列映射到我选择的 JSON 属性(即 Height__c) 由于某种原因,没有reduce(),它会导致每一列都是它自己的JSON对象,但是reduce给了我CSV的每行一个对象 然后使用“attributeThis”函数,我能够将“属性”及其“类型”连接到每个对象上,并且该类型是从 objectProperties 输入中提取的。

这允许 100% 通用 DataWeave 脚本,可以采用任何 CSV 文件并根据 3 个输入文件将其转换为任何 Salesforce 对象: CSV 文件 字段映射文件(json 格式) 对象属性文件(json 格式)

我不知道如何向 DataWeave 提供单个字符串,因此对象属性文件过于复杂

但请记住,这不会直接为您提供 SObject 列表,在 Apex 代码中,您必须反序列化 DataWeave 的输出。

下面是我可以在 Flow 中调用的 Apex 代码。

这允许我在 Flow 中提示输入 CSV 文件,然后将数据插入或更新插入到 Salesforce 中

这是我的 Apex 代码(请注意:这是一个概念证明,代码很粗糙,未注释,并且在准备好进入黄金时段之前还有很长的路要走)

/**
 * Created by Caleb Sidel on 12/12/24.
 */

public class CSVData
{
    public class FlowInput
    {
        @InvocableVariable(Label='Content Document Ids' required=true)
        public List<String> contentDocumentIds;

        @InvocableVariable(Label='Field Mappings' required=true)
        public String jsonFieldMappings;

        @InvocableVariable(Label='Object Name' required=true)
        public String objectName;
    }

    @InvocableMethod(label='Read Requirements CSV File')
    public static List<List<SObject>> readRequirementsCSVFile(List<FlowInput> inputs)
    {
        List<List<SObject>> resultList = new List<List<SObject>>();

        ContentVersion doc = [SELECT Id, VersionData FROM ContentVersion WHERE ContentDocumentId = :inputs[0].contentDocumentIds[0] AND IsLatest = TRUE];

        System.debug('inputs[0].objectName = ' + inputs[0].objectName);

        Map<String, String> objectPropertiesMap = new Map<String, String>();
        objectPropertiesMap.put('ObjectName',inputs[0].objectName);
        String jsonObjectProperties = JSON.serialize(objectPropertiesMap);
        System.debug('jsonObjectProperties = ' + jsonObjectProperties);

        Blob csvFileBody = doc.VersionData;
        String csvAsString = csvFileBody.toString();
        DataWeave.Script dwscript = new DataWeaveScriptResource.RequirementsFromCSV();
        DataWeave.Result dwresult = dwscript.execute(new Map<String, Object>{
               'csvData' => csvAsString,
               'fieldMappings' => inputs[0].jsonFieldMappings,
               'objectProperties' => jsonObjectProperties
        });

        System.debug('dwresult = ' + dwresult);
        System.debug('dwresult.getValue() = ' + dwresult.getValue());
        System.debug('dwresult.getValueAsString() = ' + dwresult.getValueAsString());

        //So our DataWeave results in a JSON string that represents a list of SObjects
        String jsonText = dwresult.getValueAsString();
        System.debug(jsonText);
        
        List<SObject> sObjectList = (List<SObject>)JSON.deserialize(jsonText,List<Sobject>.class);
        resultList.add(sObjectList);
        return resultList;
    }
}

综上所述——可能有更优雅的DataWeave脚本,并且可能有动态使用的方法

as Object

直接,但目前我很满意我有东西(任何东西)可以工作。

如果您是 DataWeave 专家,并且您对动态对象有任何想法,那就太棒了!谢谢您,祝您有美好的一天!

© www.soinside.com 2019 - 2024. All rights reserved.