Search code examples
c#asp.net-mvclinqdynamic-linq

Dynamic LINQ with Skip and Take causes Exception: Unknown LINQ expression of type 'Dynamic'


I'm building a report builder/runner using System.Linq.Dynamic.Core (1.2.20) in an ASP.NET MVC (5.2.9) app and I mostly have it working, except for one annoying issue. I can't get Skip and Take to work. Basically my code is doing this:

_context.SetDynamic("ENTITY_NAME")
        .Where(_parsingConfig, WHERE_EXPRESSION)
        .OrderBy(_parsingConfig, ORDER_BY_EXPRESSION)
        .Skip(???)// exception
        .Take(???)// exception
        .Select(_parsingConfig, SELECT_EXPRESSION)
        .ToDynamicListAsync();

Running that causes this exception:

Unknown LINQ expression of type 'Dynamic'.

When I remove Skip and Take then it works correctly and I see the results, but I lose out on the paging capabilities.

From what I can tell, it has to do with me starting out with SetDynamic which returns an IQueryable<object>. Elsewhere in the app I do the same query, but start out from a Set<T> and there's no problems with it.

What should I do to get Skip and Take to work?


Solution

  • After some more trial and error I got it to work. I manually tested switching to Set(Type) to see if it fixed Skip and Take and it did.

    From there I decided to change the model for Report to contain a string Object property. It already had an ObjectType property which was an enum, but I decided to replace it with a string, and I'll probably do that everywhere else I use it and just remove it.

    After that, using reflection I got all objects in the DbContext assembly that implement a marker interface called IEntity and projected them into an IList<Entity>:

    public sealed class Entity {
        public string DisplayName { get; set; }
        public string Name { get; set; }
        public Type Type { get; set; }
    }
    

    ... and then stored them as a singleton for dependency injection. In the report runner class since I already know the report Id I just pull it out of the database and then pull out the Entity where Report.Object == Entity.Name from the list and pass the type off to Set(Type).

    Kind of long winded, but it works. I had been planning to have something like that list for a little while so I can present it as drop down list when a new report is being created so the report runner knows where to start from when building the query.