Skip to content

Result of left joining a nullable nominal type should be null (i.e. no instance) and not an instance with all null property values #22517

Open

Description

@skclusive

when Blog does not have a Post, following query does not work in 5.0.0-preview.8.* or 6.0.0-* nightly. but works in 5.0.0-preview.7.*

 public class Blog
    {
        public int BlogId { get; set; }
        public string Url { get; set; }

        [NotMapped]
        public Post Post { get; set; }

        public List<Post> Posts { get; set; } = new List<Post>();
    }

    public class Post
    {
        public int PostId { get; set; }

        public string Title { get; set; }

        public string Content { get; set; }

        public int BlogId { get; set; }

        public Blog Blog { get; set; }
    }

// this IQueryable would come from other API.

 var dbPosts = from p in db.Posts
                          // select p;
                         select new Post
                         {
                             PostId = p.PostId,
                             BlogId = p.BlogId,
                             Content = p.Content
                         };

 var query = from blog in db.Blogs
                    join post in dbPosts on blog.BlogId equals post.BlogId into posts
                    from xpost in posts.DefaultIfEmpty()
                    select new Blog
                    {
                         Url = blog.Url,
                         Post = xpost
                   };

Steps to reproduce

I have a repo to reproduce the bug.

https://github.com/skclusive/EFLeftJoinBug

Unhandled exception. System.InvalidOperationException: Nullable object must have a value.
   at lambda_method17(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()

Further technical details

EF Core version:
Database provider: (e.g. Microsoft.EntityFrameworkCore.Sqlite)
Target framework: (e.g. .NET Core 5.0)
Operating system:
IDE: (e.g. Visual Studio Code)

Activity

  1. ajcvickers commented on Sep 12, 2020

    @ajcvickers
    Contributor

    Confirmed this works in 3.1, but fails in latest daily, on SQL Server and SQLite.

  2. smitpatel commented on Sep 13, 2020

    @smitpatel
    Contributor

    @ajcvickers - What is the generated SQL? Can you post query plan?

  3. ajcvickers commented on Sep 13, 2020

    @ajcvickers
    Contributor

    @smitpatel Here's the logs:

    dbug: Microsoft.EntityFrameworkCore.Query[10111]
          Compiling query expression: 
          'DbSet<Blog>()
              .GroupJoin(
                  inner: DbSet<Post>()
                      .Select(p => new Post{ 
                          PostId = p.PostId, 
                          BlogId = p.BlogId, 
                          Content = p.Content 
                      }
                      ), 
                  outerKeySelector: blog => blog.BlogId, 
                  innerKeySelector: post => post.BlogId, 
                  resultSelector: (blog, posts) => new { 
                      blog = blog, 
                      posts = posts
                   })
              .SelectMany(
                  collectionSelector: <>h__TransparentIdentifier0 => <>h__TransparentIdentifier0.posts
                      .DefaultIfEmpty(), 
                  resultSelector: (<>h__TransparentIdentifier0, xpost) => new Blog{ 
                      Url = <>h__TransparentIdentifier0.blog.Url, 
                      Post = xpost 
                  }
              )'
    dbug: Microsoft.EntityFrameworkCore.Query[10107]
          queryContext => new SingleQueryingEnumerable<Blog>(
              (RelationalQueryContext)queryContext, 
              RelationalCommandCache.SelectExpression(
                  Projection Mapping:
                      Url -> 0
                      Post.PostId -> 1
                      Post.BlogId -> 2
                      Post.Content -> 3
                  SELECT b.Url, p.PostId, p.BlogId, p.Content
                  FROM Blogs AS b
                  LEFT JOIN Posts AS p ON b.BlogId == p.BlogId), 
              Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, Blog>, 
              EFLeftJoinBug.BloggingContext, 
              False, 
              False
          )
    dbug: Microsoft.EntityFrameworkCore.Database.Command[20103]
          Creating DbCommand for 'ExecuteReader'.
    dbug: Microsoft.EntityFrameworkCore.Database.Command[20104]
          Created DbCommand for 'ExecuteReader' (0ms).
    dbug: Microsoft.EntityFrameworkCore.Database.Connection[20000]
          Opening connection to database 'Test' on server '(local)'.
    dbug: Microsoft.EntityFrameworkCore.Database.Connection[20001]
          Opened connection to database 'Test' on server '(local)'.
    dbug: Microsoft.EntityFrameworkCore.Database.Command[20100]
          Executing DbCommand [Parameters=[], CommandType='Text', CommandTimeout='30']
          SELECT [b].[Url], [p].[PostId], [p].[BlogId], [p].[Content]
          FROM [Blogs] AS [b]
          LEFT JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
    info: Microsoft.EntityFrameworkCore.Database.Command[20101]
          Executed DbCommand (7ms) [Parameters=[], CommandType='Text', CommandTimeout='30']
          SELECT [b].[Url], [p].[PostId], [p].[BlogId], [p].[Content]
          FROM [Blogs] AS [b]
          LEFT JOIN [Posts] AS [p] ON [b].[BlogId] = [p].[BlogId]
    fail: Microsoft.EntityFrameworkCore.Query[10100]
          An exception occurred while iterating over the results of a query for context type 'EFLeftJoinBug.BloggingContext'.
          System.InvalidOperationException: Nullable object must have a value.
             at lambda_method(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
             at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
    System.InvalidOperationException: Nullable object must have a value.
       at lambda_method(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
       at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
    Unhandled exception. System.InvalidOperationException: Nullable object must have a value.
       at lambda_method(Closure , QueryContext , DbDataReader , ResultContext , SingleQueryResultCoordinator )
       at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
       at EFLeftJoinBug.Program.Main(String[] args) in /home/ajcvickers/AllTogetherNow/Daily/Daily.cs:line 43
    
  4. self-assigned this
    on Sep 14, 2020
  5. changed the title [-]Nullable object must have a value. SingleQueryResultCoordinator.[/-] [+]Nullable object must have a value when left join-ing a nominal type[/+] on Sep 14, 2020
  6. changed the title [-]Nullable object must have a value when left join-ing a nominal type[/-] [+]Nullable object must have a value when left joining a nominal type[/+] on Sep 14, 2020
  7. smitpatel commented on Sep 14, 2020

    @smitpatel
    Contributor

    SingleQueryResultCoordinator is not the error. We are probably trying to materialize null into something which is non-nullable which should have been skipped from materialization.

  8. added this to the milestone on Sep 14, 2020
  9. smitpatel commented on Sep 14, 2020

    @smitpatel
    Contributor

    Note: This gave incorrect result in 3.1.x by initialize post with default values rather than returning null (the result of DefaultIfEmpty).

    With #20633 fixed, it now throws error.

    Right fix would be not to create instance if no rows matched.

  10. 77 remaining items

  11. modified the milestones: 11.0.0, Backlog on Jun 9, 2026
  12. ajcvickers commented on Jun 27, 2026

    @ajcvickers
    Contributor

    Follow up work after #38479:

    All are sub-cases of the umbrella #22517 unless noted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

area-queryblockedcustomer-reportedpriority-bugIssues which requires API breaks and have bigger impact hence should be fixed earlier in the release

Type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions