Skip to content

RC1: UnreachableException when loading with proxies and a JSON-mapped complex property #31597

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

Closed
ajcvickers opened this issue Aug 31, 2023 · 2 comments · Fixed by #31656
Closed

Comments

@ajcvickers
Copy link
Contributor

Minimal repro:

await using var context = new BlogsContext();
await context.Database.EnsureDeletedAsync();
await context.Database.EnsureCreatedAsync();
await context.Seed();

context.ChangeTracker.Clear();

var blogs = await context.Blogs.ToListAsync();
context.Entry(blogs[0]).Collection(e => e.Posts).Load();

public class Blog
{
    public int Id { get; private set; }
    public string Name { get; set; } = null!;
    public virtual List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; private set; }
    public string Title { get; set; } = null!;
    public int BlogId { get; set; }
    public virtual Blog Blog { get; set; } = null!;
    public PostMetadata? Metadata { get; set; }
}

public class PostMetadata
{
    public int Views { get; set; }
}

public class BlogsContext : DbContext
{
    public DbSet<Blog> Blogs
        => Set<Blog>();

    public DbSet<Post> Posts
        => Set<Post>();

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder
            .UseSqlServer(@"Data Source=(LocalDb)\MSSQLLocalDB;Database=AllTogetherNow")
            .UseLazyLoadingProxies()
            .LogTo(Console.WriteLine, LogLevel.Information)
            .EnableSensitiveDataLogging();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>().OwnsOne(
            post => post.Metadata, ownedNavigationBuilder =>
            {
                ownedNavigationBuilder.ToJson();
            });

        base.OnModelCreating(modelBuilder);
    }

    public async Task Seed()
    {
        var blogs = new List<Blog>
        {
            new()
            {
                Name = ".NET Blog",
                Posts =
                {
                    new() { Title = "Productivity comes to .NET MAUI in Visual Studio 2022" },
                    new() { Title = "Announcing .NET 7 Preview 7" },
                    new() { Title = "ASP.NET Core updates in .NET 7 Preview 7" },
                    new() { Title = "Announcing Entity Framework 7 Preview 7: Interceptors!" }
                }
            },
            new()
            {
                Name = "1unicorn2",
                Posts =
                {
                    new() { Title = "Hacking my Sixth Form College network in 1991" },
                    new() { Title = "All your versions are belong to us" },
                    new() { Title = "Moving to Linux" },
                    new() { Title = "Welcome to One Unicorn 2.0!" }
                }
            }
        };

        await AddRangeAsync(blogs);
        await SaveChangesAsync();
    }
}

Exception:

Unhandled exception. System.Diagnostics.UnreachableException: The program executed an instruction that was thought to be unreachable.
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.JsonEntityMaterializerRewriter.VisitSwitch(SwitchExpression switchExpression)
   at System.Linq.Expressions.ExpressionVisitor.VisitBinary(BinaryExpression node)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
   at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node)
   at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.JsonEntityMaterializerRewriter.VisitConditional(ConditionalExpression conditionalExpression)
   at System.Linq.Expressions.ExpressionVisitor.VisitConditional(ConditionalExpression node)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.JsonEntityMaterializerRewriter.VisitConditional(ConditionalExpression conditionalExpression)
   at System.Dynamic.Utils.ExpressionVisitorUtils.VisitBlockExpressions(ExpressionVisitor visitor, BlockExpression block)
   at System.Linq.Expressions.ExpressionVisitor.VisitBlock(BlockExpression node)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.JsonEntityMaterializerRewriter.Rewrite(BlockExpression jsonEntityShaperMaterializer)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.CreateJsonShapers(IEntityType entityType, Boolean nullable, ParameterExpression jsonReaderDataParameter, ParameterExpression keyValuesParameter, Expression parentEntityExpression, INavigation navigation)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.ShaperProcessingExpressionVisitor.ProcessShaper(Expression shaperExpression, RelationalCommandCache& relationalCommandCache, IReadOnlyList`1& readerColumns, LambdaExpression& relatedDataLoaders, Int32& collectionId)       
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitShapedQuery(ShapedQueryExpression shapedQueryExpression)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.Query.RelationalShapedQueryCompilingExpressionVisitor.VisitExtension(Expression extensionExpression)
   at Microsoft.EntityFrameworkCore.Query.QueryCompilationContext.CreateQueryExecutor[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Storage.Database.CompileQuery[TResult](Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.CompileQueryCore[TResult](IDatabase database, Expression query, IModel model, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.<>c__DisplayClass9_0`1.<Execute>b__0()
   at Microsoft.EntityFrameworkCore.Query.Internal.CompiledQueryCache.GetOrAddQuery[TResult](Object cacheKey, Func`1 compiler)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.GetEnumerator()
   at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.Load[TSource](IQueryable`1 source)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinder`1.Load(INavigation navigation, InternalEntityEntry entry, LoadOptions options)
   at Microsoft.EntityFrameworkCore.Internal.EntityFinderCollectionLoaderAdapter.Load(InternalEntityEntry entry, LoadOptions options)
   at Microsoft.EntityFrameworkCore.ChangeTracking.CollectionEntry.Load(LoadOptions options)
   at Microsoft.EntityFrameworkCore.ChangeTracking.CollectionEntry.Load()
   at Program.<Main>$(String[] args) in C:\local\code\AllTogetherNow\Daily\Daily.cs:line 15
   at Program.<Main>$(String[] args) in C:\local\code\AllTogetherNow\Daily\Daily.cs:line 15
   at Program.<Main>(String[] args)
@ajcvickers
Copy link
Contributor Author

/cc @maumar

@maumar
Copy link
Contributor

maumar commented Sep 6, 2023

when processing entity materialization code, adapting it for JSON, we assume the entity type can be a result of BlockExpression (normal case) or a NewExpression (when the ctor is the only thing and we don't need to do any other assignments). However, for proxies, the block is wrapped around Convert node, since the instance generated of of Proxy type, but we expect the actual type there.

@maumar maumar added this to the 8.0.0 milestone Sep 6, 2023
maumar added a commit that referenced this issue Sep 6, 2023
…nd a JSON-mapped complex property

when processing entity materialization code, adapting it for JSON, we assume the entity type can be a result of BlockExpression (normal case) or a NewExpression (when the ctor is the only thing and we don't need to do any other assignments). However, for proxies, the block is wrapped around Convert node, since the instance generated of of Proxy type, but we expect the actual type there.

Fix is to handle this case and push the convert inside the block to normalize the expression we produce.

Fixes #31597
maumar added a commit that referenced this issue Sep 6, 2023
…nd a JSON-mapped complex property

when processing entity materialization code, adapting it for JSON, we assume the entity type can be a result of BlockExpression (normal case) or a NewExpression (when the ctor is the only thing and we don't need to do any other assignments). However, for proxies, the block is wrapped around Convert node, since the instance generated of of Proxy type, but we expect the actual type there.

Fix is to handle this case and push the convert inside the block to normalize the expression we produce.

Fixes #31597
maumar added a commit that referenced this issue Sep 7, 2023
…nd a JSON-mapped complex property (#31656)

when processing entity materialization code, adapting it for JSON, we assume the entity type can be a result of BlockExpression (normal case) or a NewExpression (when the ctor is the only thing and we don't need to do any other assignments). However, for proxies, the block is wrapped around Convert node, since the instance generated of of Proxy type, but we expect the actual type there.

Fix is to handle this case and push the convert inside the block to normalize the expression we produce.

Fixes #31597
@ajcvickers ajcvickers modified the milestones: 8.0.0, 8.0.0-rc2 Sep 8, 2023
@ajcvickers ajcvickers modified the milestones: 8.0.0-rc2, 8.0.0 Nov 14, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants