0

我正在尝试使用 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 之间的这种差异?

4

2 回答 2

2

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

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

您的查询看起来很简单,但它失败了。也许你可以不用排队_.cgk_quotetypecode != null &&。我想这不是必需的,并且与对同一属性的后续过滤相结合,它可能会欺骗 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);
于 2021-11-08T18:26:57.757 回答
0

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

下面是我的查询的外观的一个想法。我会继续添加/修改where子句,直到查询返回我所期望的。我们可以使用&&运算符而不是多个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();
}
于 2021-11-18T17:32:25.657 回答