NetSuite 自定义记录搜索将结果转换为 .NET 对象列表

NetSuite Custom Record Search Convert Results into List of .NET Objects

我能够做到这一点的唯一方法是通过下面的基于反射的代码。我不敢相信没有 "easier NetSuite way" 可以做到这一点?我缺少一些基本的东西吗?

在对自定义对象执行搜索后,我得到了一个 Record[] 数组,然后可以对其进行循环并将每个项目转换为 CustomObject.

自定义对象的属性存储在 CustomRecordcustomFieldList 中,但不能立即访问这些值,您必须将 those他们真正的 NetSuite 类型(如 LongCustomFieldRefDoubleCustomFieldRefBooleanCustomFieldRefStringCustomFieldRef 等)。

为了不必为这些乱七八糟的事情而烦恼,我决定采用以下方法:

使用 属性 名称创建 classes 匹配(包括大小写)NetSuite 名称并继承自 NetSuiteBase(定义如下)

public class MyNetSuiteObject : NetSuiteBase //<-- Note base class
{
    public string myProperty1 { get; set; }
    public bool myProperty2 { get; set; }
    public int myProperty3 { get; set; }

    public static MyNetSuiteObject FromCustomSearchRecord(CustomRecord customRecord)
    {
        var ret = new MyNetSuiteObject();
        ret.AssignProperties(customRecord);
        return ret;
    }
}

创建一个基础 class,它将检查 CustomRecords 并将 属性 值应用于 .NET classes

public class NetSuiteBase
{

    public void AssignProperties(CustomRecord customRecord)
    {
        var classProps = this.GetType().GetProperties();
        foreach (var prop in classProps)
        {
            var propName = prop.Name;
            var propValue = prop.GetValue(this, null);

            //get the matching CustomFieldRef out of the customFieldList for the CustomRecord which matches our current property name
            var myCustomFieldRef = customRecord.customFieldList.Where(c => c.scriptId == propName).FirstOrDefault();

            if (myCustomFieldRef == null) continue;

            //we can't get the value out until we cast the CustomFieldRef to its "actual" type.
            var custType = myCustomFieldRef.GetType().Name;
            switch (custType)
            {
                case "LongCustomFieldRef":
                    TrySetProperty(prop, ((LongCustomFieldRef)myCustomFieldRef).value.ToString());
                    break;

                case "DoubleCustomFieldRef":
                    TrySetProperty(prop, ((DoubleCustomFieldRef)myCustomFieldRef).value.ToString());
                    break;

                case "BooleanCustomFieldRef":
                    TrySetProperty(prop, ((BooleanCustomFieldRef)myCustomFieldRef).value.ToString());
                    break;

                case "StringCustomFieldRef":
                    TrySetProperty(prop, ((StringCustomFieldRef)myCustomFieldRef).value.ToString());
                    break;

                case "DateCustomFieldRef":
                    TrySetProperty(prop, ((DateCustomFieldRef)myCustomFieldRef).value.ToString());
                    break;

                case "SelectCustomFieldRef":
                    TrySetProperty(prop, ((SelectCustomFieldRef)myCustomFieldRef).value.name.ToString());
                    break;

                case "MultiSelectCustomFieldRef":
                    TrySetProperty(prop, ((MultiSelectCustomFieldRef)myCustomFieldRef).value.ToString());
                    break;
                default:
                    Console.WriteLine("Unknown type: " + myCustomFieldRef.internalId);
                    break;
            }
        }
    }


    //Some of the NetSuite properties are represented as strings (I'm looking at you BOOLs), so we pass all the values from above
    //as strings and them process/attempt casts
    private void TrySetProperty(PropertyInfo prop, string value)
    {
        value = value.ToLower().Trim();

        if (prop.PropertyType == typeof(string))
        {
            prop.SetValue(this, value);
            return;
        }


        if (prop.PropertyType == typeof(bool))
        {
            if (value == "yes") value = "true";
            if (value == "no") value = "false";
            if (value == "1") value = "true";
            if (value == "0") value = "false";

            bool test;
            if (bool.TryParse(value, out test))
            {
                prop.SetValue(this, test);
                return;
            }
        }

        if (prop.PropertyType == typeof(int))
        {
            int test;
            if (int.TryParse(value, out test))
            {
                prop.SetValue(this, test);
                return;
            }
        }

        if (prop.PropertyType == typeof(double))
        {
            double test;
            if (double.TryParse(value, out test))
            {
                prop.SetValue(this, test);
                return;
            }
        }

        if (prop.PropertyType == typeof(decimal))
        {
            decimal test;
            if (decimal.TryParse(value, out test))
            {
                prop.SetValue(this, test);
                return;
            }
        }

    }
}

对自定义对象执行 NetSuite 搜索后,遍历结果并使用上述 classes 将 NetSuite 结果转换为 .NET class

for (int i = 0, j = 0; i < records.Length; i++, j++)
{
    customRecord = (CustomRecord)records[i];

    var myNetSuiteObject = MyNetSuiteObject.FromCustomSearchRecord(customRecord);
}

是否还有其他 "NetSuite way" 可以完成我上面的内容?

不,没有 "NetSuite" 方法。如果你问我,你所做的远远超出了职责范围,这太棒了。 NetSuite/SuiteTalk WSDL 太可怕了,在设计过程中做出了如此多的错误选择,令我震惊的是它按原样发布给开发人员而没有提出任何问题。下面是另一个例子。

这来自他们的 SuiteTalk 课程的文档,该文档揭示了在解析高级搜索的结果时,它们包含 SearchRowBasic 对象。在每个 SearchRowBasic 对象中都有多个字段。要访问这些字段的值,您必须获取 SearchColumnField 数组的第一个元素。你为什么要这样做?如果永远只有一个值(他们在文档中声明是的,确实永远只有一个值),为什么你要把 return 对象变成一个数组而不是仅仅传回给开发人员原始类型本身的值直接???那是非常糟糕的 API 构造,迫使开发人员每次都使用 SearchColumnField[0].searchValue 而不仅仅是 SearchColumnField.searchValue!