Skip to content

System.NotImplementedException for Precompiled Query with detailed errors enabled #34393

Open
@ChrisJollyAU

Description

@ChrisJollyAU

I am busy adding the PrecompiledQuery functionality to EFCore.Jet provider including its test suite and have run into an error I'm not sure about

When running a test (e.g. BinaryExpression) in PrecompiledQueryJetTest (outside of naming and such pretty much similar to PrecompiledQuerySqlServerTest), I end up with the following error

 Precompilation error: System.NotImplementedException: The method or operation is not implemented.
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitTry(TryExpression tryNode)
   at System.Linq.Expressions.TryExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Translate[T](Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.TranslateList(IReadOnlyList`1 list)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.VisitNewArray(NewArrayExpression newArray)
   at System.Linq.Expressions.NewArrayExpression.Accept(ExpressionVisitor visitor)
   at System.Linq.Expressions.ExpressionVisitor.Visit(Expression node)
...... stack trace with a bunch of Visits
at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.Visit(Expression node)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.TranslateCore(Expression node, IReadOnlyDictionary`2 constantReplacements, ISet`1 collectedNamespaces, ISet`1 unsafeAccessors, Boolean statementContext)
   at Microsoft.EntityFrameworkCore.Query.Internal.LinqToCSharpSyntaxTranslator.TranslateExpression(Expression node, IReadOnlyDictionary`2 constantReplacements, ISet`1 collectedNamespaces, ISet`1 unsafeAccessors)
   at Microsoft.EntityFrameworkCore.Query.Internal.RuntimeModelLinqToCSharpSyntaxTranslator.TranslateExpression(Expression node, IReadOnlyDictionary`2 constantReplacements, IReadOnlyDictionary`2 memberAccessReplacements, ISet`1 collectedNamespaces, ISet`1 unsafeAccessors)
   at Microsoft.EntityFrameworkCore.Query.Internal.PrecompiledQueryCodeGenerator.GenerateQueryExecutor(IndentedStringBuilder code, Int32 queryNum, Expression queryExecutor, HashSet`1 namespaces, HashSet`1 unsafeAccessors)
   at Microsoft.EntityFrameworkCore.Query.Internal.PrecompiledQueryCodeGenerator.ProcessSyntaxTree(SyntaxTree syntaxTree, SemanticModel semanticModel, IReadOnlyList`1 locatedQueries, List`1 precompilationErrors, String suffix, ISet`1 generatedFileNames, CancellationToken cancellationToken)

  Stack Trace: 
PrecompiledQueryTestHelpers.FullSourceTest(String sourceCode, DbContextOptions dbContextOptions, Type dbContextType, Action`1 interceptorCodeAsserter, Action`1 errorAsserter, ITestOutputHelper testOutputHelper, Boolean alwaysPrintGeneratedSources, String callerName)
PrecompiledQueryTestHelpers.FullSourceTest(String sourceCode, DbContextOptions dbContextOptions, Type dbContextType, Action`1 interceptorCodeAsserter, Action`1 errorAsserter, ITestOutputHelper testOutputHelper, Boolean alwaysPrintGeneratedSources, String callerName)
PrecompiledQueryJetTest.BinaryExpression() line 31
--- End of stack trace from previous location ---

It obviously doesn't happen with Sql Server or Sqlite.

Debugging info
This seems to have something to do with the Execution Strategy being used. When it uses the default NonRetryingExecutionStrategy it comes up with the above error. However if I use the retrying execution strategy (JetRetryingExecutionStrategy or TestJetRetryingExecutionStrategy) it works fine as expected.

Further debugging brings me to the CompileQuery function within the ProcessSyntaxTree in this file https://github.com/dotnet/efcore/blob/main/src/EFCore.Design/Query/Internal/PrecompiledQueryCodeGenerator.cs#L188

It is further in the ProcessSyntaxTree function when it calls GenerateQueryExecutor that we get the error.

Looking at the debug view of the queryExecutor variable we see the following difference (only relevant part shown - not the whole view)
This is what I get with Sql Server and Sqlite

$materializationContext1 = .New Microsoft.EntityFrameworkCore.Storage.MaterializationContext(
                $emptyValueBuffer,
                $queryContext.Context);
            $instance1 = .Default(Microsoft.EntityFrameworkCore.Query.PrecompiledQueryRelationalTestBase+Blog);
            $entry1 = .Call $queryContext.TryGetEntry(
                $key,
                .NewArray System.Object[] {
                    (System.Object).Call $dataReader.GetInt32(0)
                },
                True,
                $hasNullKey1);
            .If (
                !$hasNullKey1

This is what I get on EFCore.Jet

$materializationContext1 = .New Microsoft.EntityFrameworkCore.Storage.MaterializationContext(
                $emptyValueBuffer,
                $queryContext.Context);
            $instance1 = .Default(Microsoft.EntityFrameworkCore.Query.PrecompiledQueryRelationalTestBase+Blog);
            $entry1 = .Call $queryContext.TryGetEntry(
                $key,
                .NewArray System.Object[] {
                    .Try {
                        (System.Object).Call $dataReader.GetInt32(0)
                    } .Catch (System.Exception $e) {
                        .Call Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor+ShaperProcessingExpressionVisitor.ThrowReadValueException(
                            $e,
                            .Call $dataReader.GetFieldValue(0),
                            .Constant<System.Type>(System.Object),
                            $'property: Blog.Id (int) Required PK AfterSave:ThrowProperty')
                    }
                },
                True,
                $hasNullKey1);
            .If (
                !$hasNullKey1

Note the part where the data reader call is wrapped in a try...catch. Not sure why it is being generated

As a further note, in the VisitTry function of LinqToCSharpSyntaxTranslator, the _context variable that the switch is done on is ExpressionContext.Expression hence the NotImplementedException

I know its still marked as experimental so maybe I have hit something not finished yet

SDK: .Net 9 preview 6
Visual Studio: 17.11.0 preview 7
EF Core: 9.0.0-rc.1.24374.2 ( a daily build a day or 2 after the last preview 7 so should be close to what the final preview 7 release will be)
Using the preview 6 branch of efcore to build and debug on the SQL Server and Sqlite for comparison

Any thoughts?

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions