Dynamics CRM 2016 为营销列表生成大量 Excel 文件

Dynamics CRM 2016 generates massive Excel files for marketing lists

背景
我们的一位客户每月向他们的一部分联系人发送信息和发票。这些联系人首先被添加到营销列表中,然后联系人的姓名、地址信息和 OCR 号码 提取。将这些成员导出到 Excel 文件(以便发送打印)时,我们的客户甚至在生成文件时遇到了很多问题。成功后,才发现生成的Excel文件 大小约为 550 MB,用于大约 40k 行和少于 10 列的名称和地址信息。一段时间后,我们发现 Dynamics CRM 生成了额外的 160 个隐藏列,其中不包含任何数据。删除 这些列将文件大小降低到更合理的 4 MB。这些列交替命名为 "processid" 和 "processts".

导出时不会出现此问题,例如来自高级查找的发票,所以我很想知道 Dynamics CRM 是否做了一些特别的事情,因为在这种情况下我们 运行 是导出时的插件。

详情
我们的客户使用的流程更详细如下:

  1. 活动已创建。此活动获得序列号,这是我们生成的唯一 ID。
  2. 已创建营销列表并将其连接到市场活动。
  3. 成员已添加到营销列表中。这些成员也有一个序列号,一个唯一的ID。
  4. 从营销列表形式切换到营销列表成员。
  5. 选择我们创建的自定义视图 "Export view"。在我的最小复制中,此视图仅包含联系人的完整名称以及 "generated OCR" 字段。
  6. 注册在 post 联系人检索多个上的插件被触发并根据他们的序列号加上活动的序列号为营销列表的每个成员创建一个 OCR 编号。然后将其添加到 "generated OCR" 字段。
  7. 然后将视图导出到 Excel。插件再次触发。
  8. 如果导出成功,生成的文件包含许多空列,标记为 "processid" 和 processts。


PostContactRetrieveMultiple 插件

protected override void Execute(PluginVars variables)
{
    if (variables.Context.InputParameters.Contains("Query") && variables.Context.InputParameters["Query"] is QueryExpression)
    {
        QueryExpression objQueryExpression = (QueryExpression) variables.Context.InputParameters["Query"];

        //Generate and fill the ocr number field when requested
        if (objQueryExpression.EntityName == Contact.EntityLogicalName && objQueryExpression.ColumnSet.Columns.Contains("company_generatedocr"))
        {
            if (objQueryExpression.LinkEntities.Count > 0 && objQueryExpression.LinkEntities.Count(le => le.LinkToEntityName == ListMember.EntityLogicalName) > 0)
            {
                var contacts = ((EntityCollection)variables.Context.OutputParameters["BusinessEntityCollection"]);
                Guid relatedListGuid = (Guid)objQueryExpression.LinkEntities.First(le => le.LinkToEntityName == ListMember.EntityLogicalName).LinkCriteria.Conditions[0].Values[0];
                CampaignExtensions.GenerateOcrNumbersForCollection(contacts, relatedListGuid, variables.Dao);
            }
        }
    }
}


CampaignExtensions(截取了不相关的代码)
下面使用的 OCREngine 是我们基于序列号创建 OCR 编号的工具,例如联系人和活动,以及在支付相应发票时解释创建的数字。

public static void GenerateOcrNumbersForCollection(EntityCollection entityCollection, Guid marketingListId, DataAccess dao)
{
    var campaignSequenceNumber = GetCampaignSequenceNumberFromList(marketingListId, dao);

    foreach (var entity in entityCollection.Entities)
    {
        string sequenceNumber = entity.GetSequenceValue(dao); //Get the sequence number for the contact

        var spec = new OCRSpecification();

        spec.DonorNumber = sequenceNumber;
        spec.CampaignNumber = campaignSequenceNumber;

        entity.Attributes.Add("company_generatedocr", OCREngine.GenerateOCR(spec));
    }
}


结果
为只有一个成员的营销列表导出成员时,文件仅包含一组 "processid" 和 "processts" 列(见下文)。当导出 40 000 个成员时,它包含 80 组这样的列。这些列不存在于 Dynamics CRM 的视图中。

    Complete Name    Generated OCR    processid    processts
    Henric Fröberg   800004450000165


我的问题

我们在本地使用 Dynamics CRM 2016,rollup 1 (8.1.0.359),但在安装 rollup 1 之前,我们在导出营销列表的 Excel 文件时遇到了困难。

据我们所知,平台中有一些固有的东西可以添加这些额外的列。我们已经尝试从市场营销列表中导出成员,其中只有来自默认解决方案的列,并且仍然添加了 processidprocessts 列。然而,我们能够通过观察两个事实来解决这个问题。

观察结果

  • 除了预期的列表成员 LinkEntity 之外,导出期间的查询 运行 还包含一个 LinkEntity,它执行与进程的外部连接。从高级查找查看(和导出)营销列表成员时,此 LinkEntity 不存在。
  • 添加的processidprocessts列数与查询的PageInfo.Count属性成反比。

操作数
因此,到目前为止,对查询的以下修改似乎有效:

  • 从查询中删除进程 LinkEntity
  • 增加PageInfo.Count

代码
这是通过添加 PreContactRetrieveMultiple 插件来完成的,该插件会相应地修改查询。该插件基本上是这样的:

public class PreContactRetrieveMultiple : CrmPlugin
{
    protected override void Execute(PluginVars variables)
    {
        if (variables.Context.InputParameters.Contains("Query") && variables.Context.InputParameters["Query"] is QueryExpression)
        {
            QueryExpression objQueryExpression = (QueryExpression) variables.Context.InputParameters["Query"];

            var processQuery = query.LinkEntities.FirstOrDefault(le => le.LinkFromAttributeName == "processid");
            if (processQuery != null)
            {
                query.LinkEntities.Remove(processQuery);
            }

            query.ColumnSet = new ColumnSet(query.ColumnSet.Columns.Distinct().ToArray());
            query.ColumnSet.Columns.Remove("processid");
            query.ColumnSet.Columns.Remove("processts");

            query.PageInfo.Count = 5000;
        }
    }
}

结果
由于增加了 PageInfo.Count,这意味着视图将一次加载这 5000 条记录(而不是常规的 50/100/250)。因此,加载页面通常需要一些时间,并且经常弹出 "Unresponsive page" 警告。但是稍等片刻,视图就会加载。导出时,processidprocessts 仍会显示在文件中,但随着 PageInfo.Count 的增加,数量会少得多。文件大小现在大大减少,并且对于它包含的数据量来说更合理。

问题的答案

  • 我不知道为什么要添加这些额外的列。
  • 平台似乎为获取所有数据所需的每个分页添加一次列对。
  • 上面显示的插件似乎可以减少导出文件的大小。