Why am I getting:
The method 'Where' cannot follow the method 'Select' or is not
supported. Try writing the query in terms of supported methods or call
the 'AsEnumerable' or 'ToList' method before calling unsupported
methods.
...when using the WHERE clause, like when calling:
XrmServiceContext.CreateQuery<Contact>().Project().To<Person>().Where(p => p.FirstName == "John").First();
?
This works:
XrmServiceContext.CreateQuery<Contact>().Project().To<Person>().First();
Also this works:
XrmServiceContext.CreateQuery<Contact>().Where(p => p.FirstName == "John").First();
I'm using AutoMapper QueryableExtension.
Additional info:
- I don't want to call ToList() before the Where clause. I know it will works that way.
CreateQuery<TEntity>()
returns IQueryable<TEntity>
.
It's because whatever query provider you are using isn't able to handle this. It's not invalid in the general case; in fact most query providers do support filtering after projecting. Certain query providers simply aren't as robust as others, or they are representing a query model that is less flexible/powerful than the LINQ interface (or both). As a result, LINQ operations that are correct from the C# compiler's point of view might still not be translatable by the query provider, so the best it can do is throw an exception at runtime.
Why don't you just move the where so it is before the projection? It will result in a single query being executed which filters and projects:
XrmServiceContext.CreateQuery<Contact>().Where(p => p.FirstName == "John").Project().To<Person>().First();
Looking at AutoMapper's instructions for the QueryableExtensions it has an example showing the Where clause before the projection. You need to refactor your code to support this model, as opposed to placing the Where
clause after the projection.
public List GetLinesForOrder(int orderId)
{
Mapper.CreateMap()
.ForMember(dto => dto.Item, conf => conf.MapFrom(ol => ol.Item.Name);
using (var context = new orderEntities())
{
return context.OrderLines.Where(ol => ol.OrderId == orderId)
.Project().To().ToList();
}
}
Given the limitations of Dynamic CRM's LINQ provider you should not expect AutoMapper to necessarily get the LINQ query correct.
There is actually a logic behind this design. As the developer you create a working Where
clause. You then let AutoMapper's Project().To()
define the select
statement. Since CRM's LINQ provider has support for anonymous types in it should work correctly. The purpose of projection in AutoMapper is to limit the data retrieved from each class to only that needed for the projected to class. It is not intended to write a Where
clause based on the projected to class.