服务器端Fetchxml返回不同的结果

时间:2012-07-06 15:15:12

标签: plugins dynamics-crm-2011 fetchxml

我们的一个程序允许用户通过选择视图然后点击功能区按钮批量插入相关记录。保存表单,设置标志,然后插件就可以完成它的工作。

我们正在使用带有视图选择器的子网格,以便用户动态选择或创建自己的视图。选择视图后,将显示结果数(提供的值为lte 5k)。

当插件运行fetchxml服务器端(检索userquery或savedquery,然后是Retrieve + FetchExpression)时,结果会发生变化。我们不仅获得不同数量的记录,而且还有一些记录不同。

我们的结论是,这个问题与时区有关。一些过滤器包括“on-or-after”运算符以及日期值。 例如:

<filter type="and">
  <condition attribute="modifiedon" operator="on-or-after" value="2011-01-01" />
  <condition attribute="modifiedon" operator="on-or-before" value="2011-12-31" />
</filter>

该插件以管理员身份运行。更改插件用户无效 - 就像使用FetchExpression从CRM中提取记录时不考虑当前用户时区一样。

如何确保fetchxml表达式在客户端和服务器端返回相同的结果?

可能相关:MSDN thread

感谢您的时间。

编辑:根据Daryl的建议,我运行了一条SQL跟踪。结果令人费解。客户端查询(从CRM运行,即高级查找)正确偏移日期 - 这意味着fetchxml使用用户的时区设置正确转换。服务器端的同一查询不会发生这种情况;输出SQL包含“原样”的日期过滤器,没有时区偏移量。无论查询执行上下文的来源如何,我都假设发生了相同的翻译。

编辑2:隐藏的代码区域(我的上一个调试手段)中的标志阻止插件在运行用户的上下文中实例化服务。一切都运行良好。非常感谢大家的时间和帮助,非常感谢。

1 个答案:

答案 0 :(得分:6)

使用日期时,请始终记住转换为utc,因为这就是CRM将其存储在数据库中的方式。

原生CRM高级查找将查看当前用户的时区,并在执行SQL查询之前将他们输入高级查找的任何时间转换为UTC。你的插件控件需要做同样的事情。这些是在将条件放入Fetch Xml / Linq表达式/查询表达式之前需要执行的步骤。

  1. 通过SystemUserId获取用户的UserSetting.TimeZoneCode。
  2. 从步骤1查找TimeZoneCode的TimeZoneDefinition.StandardName
  3. 通话TimeZoneInfo.FindSystemTimeZoneById()中的标准名称将来自步骤2(你可以结合步骤1和2成一个单一的查询,但我更喜欢使用来自步骤1的输入缓存步骤3的结果为轻微的性能改进。即使用TimeZoneCode作为键的字典,并使用TimeZoneInfo作为值)
  4. 使用此功能获取您将在插件查询中使用的时间的UTC值:

  5. public static DateTime ConvertTimeToUTC(DateTime time, TimeZoneInfo timeZone)
    {
        if (time.Kind != DateTimeKind.Unspecified)
        {
            // If the DateTime is created with a specific time zone(ie DateTime.Now), getting the offset will
            // blow chow if it isn't the correct time zone:
            // The UTC Offset of the local dateTime parameter does not match the offset argument.
            //Parameter name: offset
    
            // This quick check will recreate the serverLocal time as unspecified
    
            time = new DateTime(
                time.Year,
                time.Month,
                time.Day,
                time.Hour,
                time.Minute,
                time.Second,
                time.Millisecond);
    
        }
        var offest = new DateTimeOffset(time, timeZone.GetUtcOffset(time));
        return offest.UtcDateTime;
    }