Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NotSupportedException using ExpandableQuery as nested query #111

Open
dbroudy opened this issue Jan 9, 2020 · 7 comments
Open

NotSupportedException using ExpandableQuery as nested query #111

dbroudy opened this issue Jan 9, 2020 · 7 comments

Comments

@dbroudy
Copy link

dbroudy commented Jan 9, 2020

I have a number of library functions (QueryObjectAccess in this case) that perform filtering on a IQueryable, often involving PredicateBuilder. I don't want to forget to apply AsExpandable(), so I'm calling it inside these functions. Worst case up until now, AsExpandable() was a no-op that that returned the already expandable query.

I've recently added some features that use these filtered queries as criteria for other queries, for example:

productQuery = QueryObjectAccess(productQuery, user); // returns expandable query
var categoryQuery = _db.Categories.AsExpandable()
  .Where(c => productQuery.Any(p => p.Categories.Any(pc => DbFunctions.Like(pc.Category.HierarchyKey, c.HierarchyKey + "%"))))
  .Distinct();

This is causing a NotSupportedException: Unable to create a constant value of type 'Models.Product'. Only primitive types or enumeration types are supported in this context.

It seems like the ExpressionExpander could handle this, but doesn't appear to. Is there a better way to handle this?

If I change QueryObjectAccess() to call Expand on the expression instead, it works. Is that a better approach for something buried in a library?

(I realize that in case I could conditionally call AsExpandable on productQuery depending on how it was to be used, but I can't always do that)

@NetherGranite
Copy link

Is there any news on this? LINQKit making it impossible to compose Queryables is a pretty significant shortcoming, and the resulting error message is almost untracably misleading.

@a-stankevich
Copy link

a-stankevich commented Oct 25, 2022

This issue is also important for us, as we use LINQKit extensively in our project and there are a lot of shared methods returning expandable queries. Combining those queries in a single query via join, contains, etc. is currently very hard or impossible due to that issue.

From what I found so far, the problem happens only in EF6. At some point of building a query it tries to retrieve ObjectQuery instance for another subtree and this where it hits ExpandableQuery.

Since it's neither an instance of ObjectQuery nor it implements IInternalQueryAdapter, EF falls back to IEnumerable.

My guess is that the fix should be somewhere in the ExpressionVisitor where it would provide an instance of ExpandableQuery.InnerQuery instead of just ExpandableQuery. I'll continue looking into this and will hopefully provide a PR. Any hints and suggestions about where exactly the fix should be done are very welcome.

@a-stankevich
Copy link

Here's also a simple test case that can be added in DbAsyncTests.cs to reproduce the issue:

        [Fact]
        public async Task DbAsync_ExpandNestedQueries()
        {
            Expression<Func<Entity, int>> getEntityValue = e => e.Value;
            Expression<Func<RelatedEntity, int>> getRelatedEntityValue = e => e.Value;
            var query1 = _db.Entities.AsExpandable().Select(e => getEntityValue.Invoke(e));
            var query2 = _db.RelatedEntities.AsExpandable().Select(e => getRelatedEntityValue.Invoke(e));

            var query =
                from q1 in query1
                from q2 in query2
                select new { q1, q2 };

            await query.ToListAsync();
        }

Please share your ideas for a workaround if any.

@rgroenewoudt
Copy link

Any known workarounds?

@sdanyliv
Copy link
Contributor

@rgroenewoudt, post your exact query and which EF version do you use. This one should work. Issue has 4 years and probably should be closed.

@rgroenewoudt
Copy link

rgroenewoudt commented Apr 19, 2024

@rgroenewoudt, post your exact query and which EF version do you use. This one should work. Issue has 4 years and probably should be closed.

Using .NET 8 with Entity Framework 6.4.4 with LinqKit.EntityFramework 1.2.5

Example code:

var list = (from e in context.Set<Employee>().AsExpandableEF()
            let regions = context.Set<Region>().AsExpandableEF().Where(r => !r.Deleted.HasValue)
            select e).ToList();

The second AsExpandableEF() makes it fail with:

System.NotSupportedException : LINQ to Entities does not recognize the method 'System.Linq.IQueryable`1[Model.Region] AsExpandableEF[Region](System.Linq.IQueryable`1[Model.Region])' method, and this method cannot be translated into a store expression.
   at System.Data.Entity.Core.Objects.ELinq.ExpressionConverter.MethodCallTranslator.DefaultTranslator.Translate(ExpressionConverter parent, MethodCallExpression call)

We have functions wrapping our IQueryable for extra filtering, we added AsExpandableEF() to it as adding it to every query manually is not doable but it results in queries with multiple AsExpandableEF() calls.

@sdanyliv
Copy link
Contributor

sdanyliv commented Apr 19, 2024

Remove second AsExpandableEF(). It is not needed and is a problem of your query. AsExpandable is needed only once per query, before materialisation or on the root of the query. Do not put it to extra filtering.

@scottksmith95, I think it is not big deal to remove this call AsExpandableEF from Expression Tree.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants