Dynamics CRM C#SDK - 尝试获取Quote Line的名称,但字段不存在?

问题描述:

我想列出报价的报价行,同时保持通用接口足够通用,以便能够类似地显示其他实体。Dynamics CRM C#SDK - 尝试获取Quote Line的名称,但字段不存在?

为了做到这一点,我试图使用EntityMetadata中的PrimaryNameAttribute。适用于大多数实体,但对于QuoteDetail,PrimaryNameAttribute是“productidname” - 实际上并不作为QuoteDetail实体的一部分存在的属性。

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

什么给?我觉得我已经搜索了所有的谷歌,似乎没有人遇到过这个问题,所以,也许我错过了一些简单的东西。

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

QuoteDetail(喜欢的SalesOrderDetail和OpportunityProduct)是特殊的,因为它可以是关系实体的目录产品项目或写在项目,无论从productidname(产品目录从)或productdescription得到它的“名”(直写在产品中)。您需要加入相关产品以获取其名称。

如果您即将开发通用解决方案/接口,这是您需要解决的每个查找属性的问题。

如果你永远只能从连接在查找记录需要的PrimaryNameAttribute,您可以从FormattedValues收集你的“主”实体检索名称:

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

但更好/更安全:

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; 

尝试获得写在产品名称;如果它为空,尝试获取Lookup名称,如果它为null,则从假EntityReference中获取一个空字符串。

这允许无摩擦的编码,很好地解决了“这个或那个属性”。

+0

好的,谢谢。元数据中是否有可以指导我的代码根据需要引入相关实体/字段的内容?或者这是我需要硬编码到我的解决方案,以涵盖违规实体? – Yoni

+0

刚刚看到您的更新。很快就会尝试。再次感谢。 – Yoni

+0

更新示例应该给你一个总体思路。我将添加完整的代码示例,介绍如何随后提取任意属性。 – Filburt