Skip to content

Bug: IncludeGraph fails when first entity has null navigation property #1780

@Lion-Ch

Description

@Lion-Ch

Description

When using BulkInsertOrUpdate with IncludeGraph = true, if the first entity in the list has a null navigation property (Child == null), then the ChildId foreign key is not populated for subsequent parents — even if they have valid Child objects.

As a result:

  • Child entities are inserted
  • but ChildId remains null in Parent records

Sorting the list so that entities with non-null Child come first works around the issue, but it's not a proper solution.

Packages

	<PackageReference Include="EFCore.BulkExtensions.PostgreSql" Version="8.1.3" />
	<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="8.0.13" />
	<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.13" />
	<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.11">
		<PrivateAssets>all</PrivateAssets>
		<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
	</PackageReference>

Example code

using EFCore.BulkExtensions;

using Microsoft.EntityFrameworkCore;

namespace BulkInsertBugExample
{
    public class Parent
    {
        public long Id { get; set; }
        public long? ChildId { get; set; }
        public Child Child { get; set; }
    }

    public class Child
    {
        public long Id { get; set; }
        public string Name { get; set; }

        public Parent Parent { get; set; }
    }

    public class TestDbContext : DbContext
    {
        public DbSet<Parent> Parents { get; set; }
        public DbSet<Child> Children { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseNpgsql("Server=127.0.0.1;Port=5432;Database=bulk-tests;User Id=postgres;Password=postgres;");
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Parent>()
                .HasOne(p => p.Child)
                .WithOne(ch => ch.Parent)
                .HasForeignKey<Parent>(p => p.ChildId);
        }
    }

    internal class Program
    {
        static void Main(string[] args)
        {
            CreateClearDb();

            BadInsert();

            GoodInsert();

            Console.WriteLine();
        }

        private static void BadInsert()
        {
            using TestDbContext context = new TestDbContext();

            var parents = new List<Parent>
            {
                new Parent { Child = null },
                new Parent { Child = new Child { Name = "Child 1" } },
                new Parent { Child = null },
                new Parent { Child = new Child { Name = "Child 2" } },
                new Parent { Child = null },
                new Parent { Child = new Child { Name = "Child 3" } },
            };

            context.BulkInsertOrUpdate(parents, new BulkConfig
            {
                IncludeGraph = true
            });

            var parentsFromDb = context.Parents.Include(p => p.Child).ToList();

            Console.WriteLine("Parents in DB:");
            foreach (var parent in parentsFromDb)
            {
                Console.WriteLine($"Parent Id={parent.Id}, ChildId={parent.ChildId}, ChildName={parent.Child?.Name}");
            }
        }

        private static void GoodInsert()
        {
            using TestDbContext context = new TestDbContext();

            var parents = new List<Parent>
            {
                new Parent { Child = new Child { Name = "Child 4" } },
                new Parent { Child = null },
                new Parent { Child = new Child { Name = "Child 5" } },
                new Parent { Child = null },
                new Parent { Child = new Child { Name = "Child 6" } },
                new Parent { Child = null },
            };

            context.BulkInsertOrUpdate(parents, new BulkConfig
            {
                IncludeGraph = true
            });

            var parentsFromDb = context.Parents.Include(p => p.Child).ToList();

            Console.WriteLine("Parents in DB:");
            foreach (var parent in parentsFromDb)
            {
                Console.WriteLine($"Parent Id={parent.Id}, ChildId={parent.ChildId}, ChildName={parent.Child?.Name}");
            }
        }

        private static TestDbContext CreateClearDb()
        {
            using TestDbContext context = new TestDbContext();
            context.Database.EnsureDeleted();
            context.Database.EnsureCreated();
            return context;
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions