Fetch clause fails with a NotSupportedException
Description
Environment
Attachments
Activity
corpsus vitale January 19, 2011 at 5:03 PM
Will subqueries be fixed by this patch? Something similar to:
var records = session.Query<A>().Where<A>(a => a.children.TypeOf<B>().Any(b => b.Id == 1));
Stefan Wenig December 5, 2010 at 10:08 AM
1) Fetch is not broken without the fix, it's just supposed to be used in a different way. (At least that's my understanding.) If you want to add support for using fetch in any other place, it should not break in various scenarious. Otherwise it would be worse than just telling the user to put the fetch at the end of the query, IMHO.
2) I didn't get the question. I believe the current fetch implementation picks up at the scope of the last select. You move the fetch, you need to consider getting the scope right.
Dean Ward November 26, 2010 at 6:22 AM
I've attached a patch which has more test cases with it. However I don't see your point with the 'it might break other cases'. Right now it's broken anyway for Fetch and OfType. The patch fixes this scenario and doesn't break any existing unit tests.
The multiple query source case is broken in the current trunk and you're quite correct that this patch doesn't fix that. However, if you're not projecting the select then why bother fetching additional bits of it in the first place - am I missing something obvious?
Dean
Stefan Wenig November 23, 2010 at 1:51 AM
This fix only tests the simplest case of a FetchMany on a single from clause. No Fetch, no ThenFetch/ThenFetchMany, and most importantly: no fetch clause on sources that do not fit the final projection:
from x in Session.Query<X>().FetchMany (x => x.Ys)
from z in x.Zs
select z;
from x in Session.Query<X>()
from y in Session.Query<Y>().Fetch (y => y.A)
select x;
And any other number of cases where just moving the fetch result operators to the outside might not result in a valid HQL statement. For all I know, these might work fine, but then there'd need to be tests.
OTOH, you could just provide a better exception message that tells the user to move the fetching out of the query.
Dean Ward October 18, 2010 at 2:15 PM
Steve, I've attached a patch that fixes this and NH-2375, not absolutely positive it's the right way to go, but I've basically rewritten any sub-queries with Fetch or OfType result operators so that the result operator is effectively removed and then applied at it's parent's query level. This produces the correct AST for the query concerned. Hope it's OK to apply!
Cheers,
Dean
Executing the following query results in a NotSupportedException
(from s
in this.Session.Query<Supplier>().FetchMany(s => s.Products)
where s.Id == 1
select s).ToList();
System.NotSupportedException : Specified method is not supported.
at NHibernate.Hql.Ast.ANTLR.PolymorphicQuerySourceDetector.GetClassName(IASTNode querySource) in PolymorphicQuerySourceDetector.cs: line 62
at NHibernate.Hql.Ast.ANTLR.PolymorphicQuerySourceDetector.Process(IASTNode tree) in PolymorphicQuerySourceDetector.cs: line 27
at NHibernate.Hql.Ast.ANTLR.AstPolymorphicProcessor.Process() in AstPolymorphicProcessor.cs: line 30
at NHibernate.Hql.Ast.ANTLR.AstPolymorphicProcessor.Process(IASTNode ast, ISessionFactoryImplementor factory) in AstPolymorphicProcessor.cs: line 24
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IASTNode ast, String queryIdentifier, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) in ASTQueryTranslatorFactory.cs: line 33
at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory) in ASTQueryTranslatorFactory.cs: line 27
at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) in HQLExpressionQueryPlan.cs: line 34
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) in HQLExpressionQueryPlan.cs: line 23
at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory) in HQLExpressionQueryPlan.cs: line 17
at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters) in QueryPlanCache.cs: line 88
at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow) in AbstractSessionImpl.cs: line 302
at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression) in AbstractSessionImpl.cs: line 258
at NHibernate.Linq.NhQueryProvider.PrepareQuery(Expression expression, ref IQuery query, ref NhLinqExpression nhQuery) in NhQueryProvider.cs: line 42
at NHibernate.Linq.NhQueryProvider.Execute(Expression expression) in NhQueryProvider.cs: line 25
at NHibernate.Linq.NhQueryProvider.Execute(Expression expression) in NhQueryProvider.cs: line 102
at Remotion.Data.Linq.QueryableBase`1.GetEnumerator()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList(IEnumerable`1 source)
at Tests.LinqTests.OfType() in LinqTests.cs: line 55
Rewriting the query to this works:
(from s
in this.Session.Query<Supplier>()
where s.Id == 1
select s).FetchMany(s => s.Products).ToList();
This looks to be similar to NH-2375. Unit test is attached.