【问题标题】:The method 'Where' cannot follow the method 'Select' or is not supported方法“Where”不能跟随方法“Select”或不受支持
【发布时间】:2013-04-16 23:06:38
【问题描述】:

我为什么会得到:

方法'Where'不能跟随方法'Select'或者不是 支持的。尝试根据支持的方法编写查询或调用 调用不支持之前的“AsEnumerable”或“ToList”方法 方法。

...当使用 WHERE 子句时,例如调用时:

XrmServiceContext.CreateQuery<Contact>().Project().To<Person>().Where(p => p.FirstName == "John").First();

?

这行得通:

XrmServiceContext.CreateQuery<Contact>().Project().To<Person>().First();

这也有效:

XrmServiceContext.CreateQuery<Contact>().Where(p => p.FirstName == "John").First();

我正在使用AutoMapper QueryableExtension。

附加信息:

  • 我不想在 Where 子句之前调用 ToList()。我知道它会这样工作。
  • CreateQuery&lt;TEntity&gt;() 返回IQueryable&lt;TEntity&gt;。

【问题讨论】:

标签: c# linq dynamics-crm-2011 automapper iqueryable


【解决方案1】:

这是因为您使用的任何查询提供程序都无法处理此问题。一般情况下不是无效的;事实上,大多数查询提供者确实支持投影后的过滤。某些查询提供程序根本不像其他查询提供程序那么健壮,或者它们代表的查询模型不如 LINQ 接口灵活/强大(或两者兼而有之)。因此,从 C# 编译器的角度来看是正确的 LINQ 操作可能仍然无法被查询提供程序翻译,因此它所能做的最好的事情就是在运行时抛出异常。

【讨论】:

  • 如果以下返回相同的错误,但它没有返回,这将是有意义的:XrmServiceContext.CreateQuery().Where(p => p.FirstName == "John")。第一的();。所以提供者可以处理。使用 AutoMapper 时出现错误。
  • @JoaoLeme 自动映射器在内部进行投影(即它在 IQueryable 上调用 Select)。这就是将对象从Contact 映射到Person 的方式。由于您的查询提供程序(显然)在投影后无法过滤,因此这样做会中断。移除突起使其工作,移除过滤器也是如此。您可以在投影之前执行一个、另一个或过滤,只要您在投影后不过滤即可。有关更多详细信息,它确实特定于您正在使用的查询提供程序。
  • @JoaoLeme 正如 Servy 所说,它在查询提供程序中。它适用于实体框架。
  • 那么问题出在github.com/AutoMapper/AutoMapper/blob/master/src/AutoMapper/…的第42行的“选择”?没有选择就没有工作/替代方案?
  • @JoaoLeme 您可以在选择之前过滤,不选择,不过滤,在客户端而不是服务器端过滤,或者使用能够在之后处理过滤器的不同查询提供程序一个投影。
【解决方案2】:

为什么不直接移动投影前的位置?这将导致执行过滤器和项目的单个查询:

XrmServiceContext.CreateQuery<Contact>().Where(p => p.FirstName == "John").Project().To<Person>().First();

【讨论】:

  • 我将从存储库中调用它。
  • 如果在投影前 IS NOT FirstName 如何期望 AutoMapper 弄清楚如何根据 FirstName 查询源?
【解决方案3】:

查看AutoMapper's instructions for the QueryableExtensions,它有一个示例显示投影之前的 Where 子句。您需要重构代码以支持此模型,而不是将 Where 子句放在投影之后。

公共列表 GetLinesForOrder(int orderId)
{
  映射器.CreateMap()
    .ForMember(dto => dto.Item, conf => conf.MapFrom(ol => ol.Item.Name);

  使用 (var context = new orderEntities())
  {
    返回 context.OrderLines.Where(ol => ol.OrderId == orderId)
             .Project().To().ToList();
  }
}

鉴于 Dynamic CRM 的 LINQ 提供程序的局限性,您不应期望 AutoMapper 一定能正确获取 LINQ 查询。

这个设计背后其实是有逻辑的。作为开发人员,您创建一个有效的Where 子句。然后让 AutoMapper 的 Project().To() 定义 select 语句。由于 CRM 的 LINQ 提供程序支持匿名类型,因此它应该可以正常工作。 AutoMapper 中投影的目的是将每个类检索到的数据限制为仅投影到类所需的数据。不打算根据投影到类编写Where 子句。

【讨论】:

  • CRM Linq 提供商有这个限制,但 EF 没有。投影后的过滤(Where 子句)适用于 Entity 的 Framework Linq 提供程序。
  • 同意。 CRM 的 Linq 提供程序不如 EF 灵活,因为它必须转换为 CRM 的 QueryExpression 并且不能使用直接 SQL。也就是说,LINQ 提供程序有各种形状和大小,这就是为什么我建议在投影之前执行Where,以便 AutoMapper 不会修改 Where。我想不出你需要在投影后执行Where 的原因。
  • 我试图通过简单地更改我的数据访问层(存储库)来避免更改我的服务层。 “哪里”在我的服务层(业务逻辑)和我的域模型上。我可以通过调用“Repository.Table”访问我的 PM(持久模型 - 在这种情况下为 CRM)。投影之前的“Where”子句必须使用 PM 完成,因此在投影之后拥有它会容易得多,但是因为我已经能够将 linq 表达式从 DM 转换(映射)到 PM 我现在正在调整我的服务层将 linq 表达式(where 子句)作为参数传递。
猜你喜欢
  • 2012-10-18
  • 1970-01-01
  • 1970-01-01
  • 2012-03-07
  • 2015-04-30
  • 2011-05-17
  • 2023-02-20
  • 2016-10-22
  • 2020-11-24
相关资源
最近更新 更多