【问题标题】:D365 CE: difference between OrganizationServiceContext and QueryExpression through Service?D365 CE:OrganizationServiceContext 和 QueryExpression through Service 的区别?
【发布时间】:2021-12-21 05:09:23
【问题描述】:

我正在尝试使用 OrganizationServiceContext 在插件中执行 LINQ 查询,以检索一些引号。在这些报价中,我使用 .Select() 仅选择字段 cgk_totalnetprice 的值,如下所示:

quotes = OrganizationServiceContext.QuoteSet
   .Where(_ =>
      _.OpportunityId != null &&
      _.OpportunityId.Id == opportunityId &&
      _.QuoteId != currentQuote.Id &&
      (_.StatusCode.Value == (int)Quote_StatusCode.Won || _.StatusCode.Value == (int)Quote_StatusCode.WonOrder) &&
      _.cgk_quotetypecode != null &&
      (_.cgk_quotetypecode.Value == (int)QuoteTypeCode.Regular || _.cgk_quotetypecode.Value == (int)QuoteTypeCode.ServiceUnderWarranty))
   .Select(x => new Quote() { Id = x.Id, cgk_totalnetprice = x.cgk_totalnetprice})
   .ToList();

但是,在检索这些引号时,上下文不会为除一个引号之外的所有引号返回值(并且不是首先触发更新的引号,而只是一个根本没有更新的随机引号)

奇怪的部分:当我将查询重写为 QueryExpression 时,一切正常:

QueryExpression qe = new QueryExpression("quote");
//Exclude current quote
qe.Criteria.AddCondition("quoteid", ConditionOperator.NotEqual, currentQuote.Id);
//Opportunity
qe.Criteria.AddCondition("opportunityid", ConditionOperator.NotNull);
qe.Criteria.AddCondition("opportunityid", ConditionOperator.Equal, opportunityId);
//State-Status
FilterExpression statusFilter = new FilterExpression(LogicalOperator.Or);
statusFilter.AddCondition("statuscode", ConditionOperator.Equal, (int)Quote_StatusCode.Won);
statusFilter.AddCondition("statuscode", ConditionOperator.Equal, (int)Quote_StatusCode.WonOrder);
qe.Criteria.AddFilter(statusFilter);
//QuoteType
qe.Criteria.AddCondition("cgk_quotetypecode", ConditionOperator.NotNull);
FilterExpression typeFilter = new FilterExpression(LogicalOperator.Or);
typeFilter.AddCondition("cgk_quotetypecode", ConditionOperator.Equal, (int)QuoteTypeCode.Regular);
typeFilter.AddCondition("cgk_quotetypecode", ConditionOperator.Equal, (int)QuoteTypeCode.ServiceUnderWarranty);
qe.Criteria.AddFilter(typeFilter);
qe.ColumnSet = new ColumnSet("quoteid", "cgk_totalnetprice");
quotes = this.OrganizationService.RetrieveMultiple(qe).Entities.Cast<Quote>().ToList();

是什么导致了 OrganizationServiceContext 和 OrganizationService + QueryExpression 之间的这种差异??

【问题讨论】:

    标签: plugins dynamics-crm microsoft-dynamics dataverse dynamics-365-ce


    【解决方案1】:

    我通常使用 Dynamics LINQ 查询的查询语法。我建议标准查询故障排除 - 从无条件开始并逐个添加。

    下面是我的查询外观的一个想法。我会继续添加/修改where 子句,直到查询返回我所期望的。 我们可以使用&amp;&amp; 运算符代替多个where 子句,但我发现拥有多个where 子句通常会使注释和取消注释更容易。

    using(var ctx = new OrganizationServiceContext(ctx))
    {
        var x = from q in ctx.CreateQuery<Quote>()
                where q.QuoteId ! = currentQuote.Id
                where q.OpportunityId != null
                where q.cgk_quotetypecode != null 
                where q.cgk_quotetypecode == QuoteTypeCode.Regular || QuoteTypeCode.ServiceUnderWarranty    
                select new Quote
                {
                    Id = q.Id,
                    cgk_totalnetprice = x.cgk_totalnetprice
                };
        var quotes = x.ToList();
    }
    

    【讨论】:

      【解决方案2】:

      OrganizationServiceContext 上的查询依赖于 LINQ for CRM,而后者又将 LINQ 表达式转换为 QueryExpression 对象。用于 CRM 的 LINQ 有一些弱点:

      • 它没有实现底层QueryExpression的所有功能,
      • 它仅支持有限的一组 LINQ 构造(请参阅MS Docs),
      • 在某些情况下,它会创建不正确的查询,
      • 查询处理大约是。慢 10%。

      您的查询看起来很简单,但它失败了。也许您可以将_.cgk_quotetypecode != null &amp;&amp; 挂断。我想这不是必需的,并且与对同一属性的后续过滤相结合,它可能会欺骗 LINQ 解析器构造错误的过滤器和/或条件。

      另一个选项是首先实现 LINQ 查询,然后选择所需的列。当然这会导致select *,但在故障排除时通常值得尝试。

      例如你可以写:

         .ToArray()
         .Select(x => new Quote() { Id = x.Id, cgk_totalnetprice = x.cgk_totalnetprice});
      

      使用 Dynamics CRM/365 CE 我学会了避免使用 LINQ for CRM。相反,我使用了一堆扩展方法,允许我以更简洁的方式创建 QueryExpression 查询。

      最终建议:在某些情况下,过滤器的LogicalOperator.Or 可以替换为ConditionOperator.InConditionOperator.Between。这样做构造

      //State-Status
      FilterExpression statusFilter = new FilterExpression(LogicalOperator.Or);
      statusFilter.AddCondition("statuscode", ConditionOperator.Equal, (int)Quote_StatusCode.Won);
      statusFilter.AddCondition("statuscode", ConditionOperator.Equal, (int)Quote_StatusCode.WonOrder);
      qe.Criteria.AddFilter(statusFilter);
      

      可以简单地用这个oneliner替换:

      qe.Criteria.AddCondition("statuscode", ConditionOperator.In, (int)Quote_StatusCode.Won, (int)Quote_StatusCode.WonOrder);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-09-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-03-17
        • 2012-07-16
        相关资源
        最近更新 更多