Dynamics CRM C# SDK - 试图获取报价行的名称,但字段不存在?

Dynamics CRM C# SDK - Trying to get name of Quote Line, but field does not exist?

我想列出报价的报价行,同时保持界面足够通用,以便能够类似地显示其他实体。

为此,我尝试使用 EntityMetadata 中的 PrimaryNameAttribute。适用于大多数实体,但对于 QuoteDetail,PrimaryNameAttribute 是 "productidname" - 作为 QuoteDetail 实体的一部分实际上并不存在的属性。

此字段 "productidname" 也是其他实体(OpportunityProduct、SalesOrderDetail)的 PrimaryNameAttribute,在这些情况下,该字段也缺失。

什么给了?我觉得我已经搜索了所有 Google 并且之前似乎没有人 运行 进入过这个问题,所以,也许我遗漏了一些简单的东西。

这是 MSDN 的 QuoteDetail 实体页面,显示了我在说什么:https://msdn.microsoft.com/en-us/library/mt607959.aspx请注意,PrimaryNameAttribute 未在页面的其他任何位置列出。

QuoteDetail(如 SalesOrderDetail 和 OpportunityProduct)的特殊之处在于它可以是目录产品项或写入项的关系实体,并从 productidname(产品来自目录)或 productdescription(写入产品)。您需要加入相关产品才能获得其名称。

如果您要开发一个泛型 solution/interface,这是您需要为每个 Lookup 属性解决的问题。

如果您只需要查找中连接的记录中的 PrimaryNameAttribute,您可以从 "main" 实体的 FormattedValues 集合中检索名称:

string productname = quotedetail.FormattedValues["productid"];

还 better/safer:

string productname;
quotedetail.FormattedValues.TryGetValue("productid", out productname);

任意实体的处理属性可以如下所示:

foreach (var key in record.Attributes.Keys)
{
    if (record.FormattedValues.ContainsKey(key))
    {
        string formattedvalue;

        if (record.FormattedValues.TryGetValue(key, out formattedvalue))
        {
            Console.WriteLine(formattedvalue); // use formattedvalue string
        }

        continue; // skip to next field when found in formatted values
    }

    object attributevalue;

    record.Attributes.TryGetValue(key, out attributevalue);

    object actualvalue;
    string actualtext = string.Empty;

    // handle AliasedValue fields from JOINed/LinkEntities
    if (attributevalue.GetType().Name == "AliasedValue")
    {
        actualvalue = ((AliasedValue)attributevalue).Value;
    }
    else
    {
        actualvalue = attributevalue;
    }

    switch (actualvalue.GetType().Name)
    {
        case "EntityReference":
            actualtext = ((EntityReference)actualvalue).Name; // this will catch Lookup values not contained in FormattedValues when you just created them
            break;

        case "DateTime":
            actualtext = string.Format("{0:dd.MM.yyyy}", ((DateTime)actualvalue).ToLocalTime()); // ... any other dateTime format you'd like
            break;

        case "Guid":
            actualtext = string.Format("{0:D}", actualvalue); // Entity Primary key
            break;

        default:
            actualtext = (string)actualvalue; // anything else
            break;
    }

    Console.WriteLine(actualtext);
}

您仍然需要处理新分配的 OptionSetValueMoney 属性(类似于 EntityReference 属性),因为它们通常会从 FormattedValues 中提取。

由于此示例处理的是现有的 crm 数据,因此您需要意识到您的实体可能不会包含所有属性的陷阱,因此您可能不想迭代 .Attributes.Keys,而是希望遍历预定义的属性名称集合。

我的个人策略通常是创建轻量级 ORM 以在类型化对象和 CRM 实体之间进行映射,但这不符合您对通用接口的要求。


对于像你这样的情况,无论是这个还是那个属性,我都会使用语法糖来工作:

string pn = qd.GetAttributeValue<string>("productdesription") ?? (qd.GetAttributeValue<EntityReference>("productid") ?? new EntityReference { Name = string.Empty }).Name;

尝试获取Write-In产品名称;如果为空,则尝试获取查找名称,如果为空,则从假 EntityReference 获取空字符串。

这允许相当无摩擦的编码并很好地解决了 "either this or that attribute"。