Skip to content

Commit 8e4dfe6

Browse files
CopilotPhenX
andcommitted
Add tests for entity linking with generated and client-generated keys
Co-authored-by: PhenX <42170+PhenX@users.noreply.github.com>
1 parent 5f74e09 commit 8e4dfe6

1 file changed

Lines changed: 154 additions & 0 deletions

File tree

tests/PhenX.EntityFrameworkCore.BulkInsert.Tests/Tests/Graph/GraphTestsBase.cs

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -434,4 +434,158 @@ await _context.ExecuteBulkInsertAsync(new[] { blog }, options =>
434434
insertedTags.Should().HaveCount(2);
435435
insertedTags.Should().AllSatisfy(t => t.Id.Should().BeGreaterThan(0));
436436
}
437+
438+
[SkippableFact]
439+
public async Task InsertGraph_OriginalEntitiesLinked_WithGeneratedKeys()
440+
{
441+
// Arrange - Keep references to original entities
442+
var post1 = new Post { TestRun = _run, Title = $"{_run}_LinkedPost1" };
443+
var post2 = new Post { TestRun = _run, Title = $"{_run}_LinkedPost2" };
444+
var settings = new BlogSettings { TestRun = _run, EnableComments = true };
445+
var blog = new Blog
446+
{
447+
TestRun = _run,
448+
Name = $"{_run}_LinkedBlog",
449+
Posts = new List<Post> { post1, post2 },
450+
Settings = settings
451+
};
452+
453+
// Act
454+
await _context.ExecuteBulkInsertAsync(new[] { blog }, options =>
455+
{
456+
options.IncludeGraph = true;
457+
});
458+
459+
// Assert - Verify the original entity references are the same objects
460+
// and have their generated IDs populated
461+
blog.Id.Should().BeGreaterThan(0, "Blog should have generated ID populated");
462+
post1.Id.Should().BeGreaterThan(0, "Post1 should have generated ID populated");
463+
post2.Id.Should().BeGreaterThan(0, "Post2 should have generated ID populated");
464+
settings.Id.Should().BeGreaterThan(0, "Settings should have generated ID populated");
465+
466+
// Verify FK values are propagated
467+
post1.BlogId.Should().Be(blog.Id, "Post1.BlogId should reference the Blog");
468+
post2.BlogId.Should().Be(blog.Id, "Post2.BlogId should reference the Blog");
469+
settings.BlogId.Should().Be(blog.Id, "Settings.BlogId should reference the Blog");
470+
471+
// Verify the same objects are in the collections
472+
blog.Posts.Should().Contain(post1, "Original post1 reference should still be in the collection");
473+
blog.Posts.Should().Contain(post2, "Original post2 reference should still be in the collection");
474+
blog.Settings.Should().BeSameAs(settings, "Original settings reference should still be assigned");
475+
476+
// Verify data matches what's in the database
477+
var dbBlog = _context.Blogs.FirstOrDefault(b => b.Id == blog.Id);
478+
dbBlog.Should().NotBeNull();
479+
dbBlog!.Name.Should().Be(blog.Name);
480+
481+
var dbPosts = _context.Posts.Where(p => p.BlogId == blog.Id).ToList();
482+
dbPosts.Should().HaveCount(2);
483+
dbPosts.Select(p => p.Id).Should().Contain(post1.Id);
484+
dbPosts.Select(p => p.Id).Should().Contain(post2.Id);
485+
}
486+
487+
[SkippableFact]
488+
public async Task InsertGraph_OriginalEntitiesLinked_WithClientGeneratedKeys()
489+
{
490+
// Arrange - Create entities with pre-set GUIDs (client-generated keys)
491+
// Using TestEntityWithGuidId which has ValueGeneratedNever()
492+
var guid1 = Guid.NewGuid();
493+
var guid2 = Guid.NewGuid();
494+
495+
var entity1 = new TestEntityWithGuidId
496+
{
497+
TestRun = _run,
498+
Id = guid1,
499+
Name = $"{_run}_ClientGenKey1"
500+
};
501+
var entity2 = new TestEntityWithGuidId
502+
{
503+
TestRun = _run,
504+
Id = guid2,
505+
Name = $"{_run}_ClientGenKey2"
506+
};
507+
508+
// Act - Insert without graph (since these don't have navigations)
509+
// but test that client-generated keys are preserved
510+
await _context.ExecuteBulkInsertAsync(new[] { entity1, entity2 }, options =>
511+
{
512+
// No IncludeGraph needed since no navigations
513+
});
514+
515+
// Assert - Verify the original entity references maintain their IDs
516+
entity1.Id.Should().Be(guid1, "Entity1 should retain its client-generated ID");
517+
entity2.Id.Should().Be(guid2, "Entity2 should retain its client-generated ID");
518+
519+
// Verify data is in database with the same IDs
520+
var dbEntity1 = _context.TestEntitiesWithGuidId.FirstOrDefault(e => e.Id == guid1);
521+
var dbEntity2 = _context.TestEntitiesWithGuidId.FirstOrDefault(e => e.Id == guid2);
522+
523+
dbEntity1.Should().NotBeNull();
524+
dbEntity2.Should().NotBeNull();
525+
dbEntity1!.Name.Should().Be(entity1.Name);
526+
dbEntity2!.Name.Should().Be(entity2.Name);
527+
}
528+
529+
[SkippableFact]
530+
public async Task InsertGraph_MultipleRootEntities_OriginalEntitiesLinked()
531+
{
532+
// Arrange - Multiple root entities with children, keep all references
533+
var post1 = new Post { TestRun = _run, Title = $"{_run}_Multi1Post1" };
534+
var post2 = new Post { TestRun = _run, Title = $"{_run}_Multi2Post1" };
535+
var post3 = new Post { TestRun = _run, Title = $"{_run}_Multi2Post2" };
536+
537+
var blog1 = new Blog
538+
{
539+
TestRun = _run,
540+
Name = $"{_run}_MultiBlogLinked1",
541+
Posts = new List<Post> { post1 }
542+
};
543+
var blog2 = new Blog
544+
{
545+
TestRun = _run,
546+
Name = $"{_run}_MultiBlogLinked2",
547+
Posts = new List<Post> { post2, post3 }
548+
};
549+
550+
var blogs = new[] { blog1, blog2 };
551+
552+
// Act
553+
await _context.ExecuteBulkInsertAsync(blogs, options =>
554+
{
555+
options.IncludeGraph = true;
556+
});
557+
558+
// Assert - All original entities should have IDs and be linked correctly
559+
blog1.Id.Should().BeGreaterThan(0);
560+
blog2.Id.Should().BeGreaterThan(0);
561+
blog1.Id.Should().NotBe(blog2.Id, "Different blogs should have different IDs");
562+
563+
post1.Id.Should().BeGreaterThan(0);
564+
post2.Id.Should().BeGreaterThan(0);
565+
post3.Id.Should().BeGreaterThan(0);
566+
post1.Id.Should().NotBe(post2.Id);
567+
post2.Id.Should().NotBe(post3.Id);
568+
569+
// Verify FK relationships
570+
post1.BlogId.Should().Be(blog1.Id);
571+
post2.BlogId.Should().Be(blog2.Id);
572+
post3.BlogId.Should().Be(blog2.Id);
573+
574+
// Verify original objects are still in collections
575+
blog1.Posts.Should().Contain(post1);
576+
blog2.Posts.Should().Contain(post2);
577+
blog2.Posts.Should().Contain(post3);
578+
579+
// Verify database state matches
580+
var dbBlogs = _context.Blogs.Where(b => b.TestRun == _run).ToList();
581+
dbBlogs.Should().HaveCount(2);
582+
dbBlogs.Select(b => b.Id).Should().Contain(blog1.Id);
583+
dbBlogs.Select(b => b.Id).Should().Contain(blog2.Id);
584+
585+
var dbPosts = _context.Posts.Where(p => p.TestRun == _run).ToList();
586+
dbPosts.Should().HaveCount(3);
587+
dbPosts.Select(p => p.Id).Should().Contain(post1.Id);
588+
dbPosts.Select(p => p.Id).Should().Contain(post2.Id);
589+
dbPosts.Select(p => p.Id).Should().Contain(post3.Id);
590+
}
437591
}

0 commit comments

Comments
 (0)