Quantcast
Channel: OracleDB – The Wiert Corner – irregular stream of stuff
Viewing all articles
Browse latest Browse all 20

NHibernate, LINQ, Oracle and the placement of Take: avoid “Specified method is not supported.”

$
0
0

Even though as of 12c R1, Oracle supports a row limiting clause, NHibernate 4.2 with Oracle.DataAccess.dll 2.112.3.0 does not support that.

When you let it generate the SQL for a LINQ Take call to limit the number of results, you get an exception like this (full exception and stack trace are below):

System.NotSupportedException was unhandled by user code
  HResult=-2146233067
  Message=Specified method is not supported.

The place where you Take is important, as this does fail:

        public ResultType[] SelectByFilter(int? foreignKey,
            DateTime? startDateTime,
            DateTime? endDateTime)
        {
            if (!((foreignKey.HasValue) || (startDateTime.HasValue) || (endDateTime.HasValue)))
                throw new ArgumentException("At least one of foreignKey, startDateTime or endDateTime must have a value");

            IQueryable entities = this.repository.GetEntities();

            if (foreignKey.HasValue)
                entities = entities.Where(e => e.foreignKey == foreignKey.Value);
            if (startDateTime.HasValue)
                entities = entities.Where(e => e.CreationDateTime >= startDateTime.Value);
            if (endDateTime.HasValue)
                entities = entities.Where(e => e.CreationDateTime <= endDateTime.Value);
            entities = entities.Take(MaxSelectByFilterCount); // cause of the exception

            IQueryable resultTypes = entities.Select(
                e =>
                    new ResultType
                    {
                        ResultTypeId = e.ResultTypeEntityId,
                        ForeignKey = e.ForeignKey,
                        CreationDateTime = e.CreationDateTime,
                        CreationUserId = e.CreationUserId,
                        UpdateUserId = e.UpdateUserId
                    });

            return resultTypes.ToArray(); // line at which the Exception is fired
        }

But this succeeds:

        public ResultType[] SelectByFilter(int? foreignKey,
            DateTime? startDateTime,
            DateTime? endDateTime)
        {
            if (!((foreignKey.HasValue) || (startDateTime.HasValue) || (endDateTime.HasValue)))
                throw new ArgumentException("At least one of foreignKey, startDateTime or endDateTime must have a value");

            IQueryable entities = this.repository.GetEntities();

            if (foreignKey.HasValue)
                entities = entities.Where(e => e.foreignKey == foreignKey.Value);
            if (startDateTime.HasValue)
                entities = entities.Where(e => e.CreationDateTime >= startDateTime.Value);
            if (endDateTime.HasValue)
                entities = entities.Where(e => e.CreationDateTime <= endDateTime.Value);

            IQueryable resultTypes = entities.Select(
                e =>
                    new ResultType
                    {
                        ResultTypeId = e.ResultTypeEntityId,
                        ForeignKey = e.ForeignKey,
                        CreationDateTime = e.CreationDateTime,
                        CreationUserId = e.CreationUserId,
                        UpdateUserId = e.UpdateUserId
                    });

            resultTypes = resultTypes.Take(MaxSelectByFilterCount); // put Take here to let LINQ bypass NHibernate
            return resultTypes.ToArray(); // line at which the Exception is fired
        }

The workaround generates an Oracle query that is not limit the result set, but LINQ only fetches MaxSelectByFilterCount entries (in my case 10k). Not as optimal as it could be, but good enough.

–jeroen

System.NotSupportedException was unhandled by user code
  HResult=-2146233067
  Message=Specified method is not supported.
  Source=NHibernate
  StackTrace:
       at NHibernate.Hql.Ast.ANTLR.PolymorphicQuerySourceDetector.GetClassName(IASTNode querySource)
       at NHibernate.Hql.Ast.ANTLR.PolymorphicQuerySourceDetector.Process(IASTNode tree)
       at NHibernate.Hql.Ast.ANTLR.AstPolymorphicProcessor.Process()
       at NHibernate.Hql.Ast.ANTLR.AstPolymorphicProcessor.Process(IASTNode ast, ISessionFactoryImplementor factory)
       at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IASTNode ast, String queryIdentifier, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
       at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryIdentifier, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
       at NHibernate.Engine.Query.HQLExpressionQueryPlan.CreateTranslators(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
       at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
       at NHibernate.Engine.Query.HQLExpressionQueryPlan..ctor(String expressionStr, IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
       at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow, IDictionary`2 enabledFilters)
       at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(IQueryExpression queryExpression, Boolean shallow)
       at NHibernate.Impl.AbstractSessionImpl.CreateQuery(IQueryExpression queryExpression)
       at NHibernate.Linq.DefaultQueryProvider.PrepareQuery(Expression expression, IQuery& query, NhLinqExpression& nhQuery)
       at NHibernate.Linq.DefaultQueryProvider.Execute(Expression expression)
       at NHibernate.Linq.DefaultQueryProvider.Execute[TResult](Expression expression)
       at Remotion.Linq.QueryableBase`1.GetEnumerator()
       at System.Linq.Buffer`1..ctor(IEnumerable`1 source)
       at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)

Filed under: .NET, .NET 2.0, .NET 3.0, .NET 3.5, .NET 4.0, .NET 4.5, .NET ORM, C#, C# 2.0, C# 3.0, C# 4.0, C# 5.0, C# 6 (Roslyn), Database Development, Development, NHibernate, OracleDB, Software Development

Viewing all articles
Browse latest Browse all 20

Trending Articles