Skip to content

Commit efe9bcd

Browse files
kplochclaude
andauthored
test(integration): Seed write/UoW/audit/delete tests via a separate DbContext (#87)
* test(integration): Seed write/UoW/audit/delete tests via a separate DbContext Convert Arrange-phase fixture seeding in the remaining integration-test classes from the repository / UnitOfWork write path to a separate DbContext (RepositoryHelper.Add...(CreateRootDbContext)), completing the work begun for ReadRepositoryTests. Seeding through a separate context keeps the seeded entities out of the code-under-test's change tracker, so reads genuinely re-hydrate from the database and the fixture setup no longer depends on the write path it is meant to be independent of. Per-test classification (Arrange converted, Act left in place): - ReadWriteRepositoryAsyncTests: all 9 read-test seedings converted. - ReadWriteRepositoryDeleteByIdTests: 3 Arrange seedings converted. - UnitOfWorkRepositoryAsyncSQLiteInMemoryTests: 3 update/delete-test Arrange seedings converted; the add+commit calls in the add-and-query and AddAsync tests left repository-based (the add IS the test) with explanatory comments. - ReadWriteRepositoryAsyncAuditTests: both seedings left repository-based (the class verifies the repository write path's audit behaviour) with explanatory comments. Add DbContext and Func<DbContext> overloads to RepositoryHelper's AddTestBlogEntities helper. Fix UpdateAsync_entity, which was a vacuous self-comparison (seed and read shared one change-tracker instance) until the seed context was separated; exclude the audit columns it does not assert on. Refs: #85 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(integration): Use fetch-modify-update in UpdateAsync_entity Address PR #87 review feedback (gemini-code-assist, codeant-ai): the previous UpdateAsync_entity built a partial Blog (Id + Name only), and ReadWriteRepositoryAsync.UpdateAsync applies it via CurrentValues.SetValues, which blanks every unsupplied column — including CreatedTime. Excluding CreatedTime from the assertion masked that. Switch to the idiomatic fetch-modify-update pattern so the update payload carries every column; CreatedTime is now preserved and asserted rather than excluded. Only ModifiedTime stays excluded (UpdateAsync legitimately changes it). Refs: #85 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(integration): Deconstruct seeding tuple in FindFirstAsync test Address the SonarCloud IDE0042 finding on PR #87: the FindFirstAsync seeding result was bound to a named variable when only one element was used. Deconstruct the tuple directly (`var (_, blogPost1, _)`). Refs: #85 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * test(integration): Add DbContext seed overloads for the UserIdea helper Address PR #87 review feedback (@kploch): issue #85's acceptance criteria lists the UserIdea helpers among those needing DbContext / Func<DbContext> seed overloads. Add them to AddAsyncTestUserIdeasEntitiesAsync (real logic in the DbContext overload; the Func<DbContext> overload wraps it with await using) so future Arrange-phase UserIdea tests can seed via a separate context without falling back to the repository write path. Refs: #85 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(solution): Fix editorconfig test glob and clear SonarCloud findings The `[*Tests/**/*.cs]` editorconfig section header never matched any file. The section is anchored to the repository root and requires the first path segment to end in literal `Tests`, but test projects live under the lowercase `tests/` directory and editorconfig globs are case-sensitive. As a result the `IDE0058` ("Expression value is never used") suppression intended for test code never took effect, leaving SonarCloud to import the diagnostic for every idiomatic discard of an `EntityEntry` returned by `AddAsync`. Corrected the header to `[tests/**/*.cs]`. Also cleared the remaining SonarCloud findings on PR #87: - Renamed the new async seeding overloads `AddTestBlogEntities` to `AddTestBlogEntitiesAsync` (CC0061). - Simplified the `UserIdea` array returns to collection expressions (IDE0300). Refs: #85 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 582c83b commit efe9bcd

6 files changed

Lines changed: 172 additions & 83 deletions

File tree

.editorconfig

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -707,7 +707,7 @@ resharper_wrap_before_first_type_parameter_constraint = false
707707
dotnet_diagnostic.CC0067.severity = none
708708

709709
# Test project overrides
710-
[*Tests/**/*.cs]
710+
[tests/**/*.cs]
711711
# IDE0058: Expression value is never used — test assertions and fluent API chains
712712
# intentionally discard return values.
713713
dotnet_diagnostic.IDE0058.severity = none

tests/Data.GenericRepository/Data.GenericRepository.EFCore.IntegrationTests/ReadWriteRepositoryAsyncAuditTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ public class ReadWriteRepositoryAsyncAuditTests : GenericRepositoryDataIntegrati
99
public async Task Update_and_CommitAsync_should_set_modified_time_audit_property()
1010
{
1111
var unitOfWork = CreateUnitOfWork();
12+
13+
// Seeded through the repository on purpose: this class verifies the audit behaviour of the
14+
// repository write path, and the assertion below checks that a repository Add leaves
15+
// ModifiedTime unset. A separate-context seed would make that assertion vacuous.
1216
var (blog, _, _) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(unitOfWork.Repository<Blog, int>());
1317
await unitOfWork.CommitAsync();
1418

@@ -29,6 +33,9 @@ public async Task Add_and_CommitAsync_should_update_created_time_audit_property(
2933
{
3034
var unitOfWork = CreateUnitOfWork();
3135
var createdTime = DateTimeOffset.UtcNow;
36+
37+
// Adding through the repository and committing IS the operation under test here, so this
38+
// seeding deliberately stays repository-based.
3239
var (blog, _, _) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(unitOfWork.Repository<Blog, int>());
3340
await unitOfWork.CommitAsync();
3441

tests/Data.GenericRepository/Data.GenericRepository.EFCore.IntegrationTests/ReadWriteRepositoryAsyncTests.cs

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,9 @@ public async Task ApplySqLiteDateTimeOffsetPropertiesFix_should_handle_DateTimeO
3131
[Fact]
3232
public async Task CountAsync_should_return_entity_count()
3333
{
34-
using var unitOfWork = CreateUnitOfWork();
35-
36-
await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(unitOfWork.Repository<Blog, int>());
37-
38-
await unitOfWork.CommitAsync();
34+
// Arrange — seed via a separate context so the seeded entities are not in the read
35+
// context's change tracker; the query below genuinely round-trips through the database.
36+
await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(CreateRootDbContext);
3937

4038
var repository = CreateReadRepositoryAsync<BlogPost, int>();
4139
var count = await repository.CountAsync();
@@ -46,11 +44,9 @@ public async Task CountAsync_should_return_entity_count()
4644
[Fact]
4745
public async Task GetAllAsync_should_return_entities_with_includes()
4846
{
49-
using var unitOfWork = CreateUnitOfWork();
50-
51-
var (_, blogPost1, blogPost2) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(unitOfWork.Repository<Blog, int>());
52-
53-
await unitOfWork.CommitAsync();
47+
// Arrange — seed via a separate context so the seeded entities are not in the read
48+
// context's change tracker; the query below genuinely round-trips through the database.
49+
var (_, blogPost1, blogPost2) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(CreateRootDbContext);
5450

5551
var repository = CreateReadWriteRepositoryAsync<BlogPost, int>();
5652
var blogPosts = await repository.GetAllAsync(onDbSet: query => query.Include(e => e.Tags));
@@ -70,11 +66,9 @@ public async Task GetAllAsync_should_return_entities_with_includes()
7066
[Fact]
7167
public async Task GetAllAsync_should_return_entities_without_includes()
7268
{
73-
using var unitOfWork = CreateUnitOfWork();
74-
75-
var (_, blogPost1, blogPost2) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(unitOfWork.Repository<Blog, int>());
76-
77-
await unitOfWork.CommitAsync();
69+
// Arrange — seed via a separate context so the seeded entities are not in the read
70+
// context's change tracker; the query below genuinely round-trips through the database.
71+
var (_, blogPost1, blogPost2) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(CreateRootDbContext);
7872

7973
var repository = CreateReadWriteRepositoryAsync<BlogPost, int>();
8074
var blogPosts = await repository.GetAllAsync();
@@ -86,18 +80,16 @@ public async Task GetAllAsync_should_return_entities_without_includes()
8680
.ContainEquivalentOf(blogPost2,
8781
options => options.Excluding(p => p.Categories).Excluding(p => p.Tags).Excluding(p => p.CreatedTime).Excluding(p => p.ModifiedTime));
8882

89-
// Categories and Tags are not included in the query but they will not be empty because they are already loaded in the context.
90-
// This is why I don't check for emptiness here.
83+
// GetAllAsync() without an Include does not load Categories or Tags, so they are excluded
84+
// from the comparison.
9185
}
9286

9387
[Fact]
9488
public async Task GetPageAsync_should_return_a_page_of_entities_with_includes()
9589
{
96-
using var unitOfWork = CreateUnitOfWork();
97-
98-
var (_, posts) = await RepositoryHelper.AddAsyncTestBlogEntitiesWithManyPostsAsync(unitOfWork.Repository<Blog, int>(), 20);
99-
100-
await unitOfWork.CommitAsync();
90+
// Arrange — seed via a separate context so the seeded entities are not in the read
91+
// context's change tracker; the query below genuinely round-trips through the database.
92+
var (_, posts) = await RepositoryHelper.AddAsyncTestBlogEntitiesWithManyPostsAsync(CreateRootDbContext, 20);
10193

10294
var repository = CreateReadRepositoryAsync<BlogPost, int>();
10395

@@ -121,11 +113,9 @@ public async Task GetPageAsync_should_return_a_page_of_entities_with_includes()
121113
[Fact]
122114
public async Task GetPageAsync_should_return_a_page_of_entities_with_includes_using_query()
123115
{
124-
using var unitOfWork = CreateUnitOfWork();
125-
126-
var (_, posts) = await RepositoryHelper.AddAsyncTestBlogEntitiesWithManyPostsAsync(unitOfWork.Repository<Blog, int>(), 20);
127-
128-
await unitOfWork.CommitAsync();
116+
// Arrange — seed via a separate context so the seeded entities are not in the read
117+
// context's change tracker; the query below genuinely round-trips through the database.
118+
var (_, posts) = await RepositoryHelper.AddAsyncTestBlogEntitiesWithManyPostsAsync(CreateRootDbContext, 20);
129119

130120
var repository = CreateReadRepositoryAsync<BlogPost, int>();
131121

@@ -156,11 +146,9 @@ public async Task GetPageAsync_should_return_a_page_of_entities_with_includes_us
156146
[Fact]
157147
public async Task GetPageAsync_should_return_a_page_of_entities_without_includes()
158148
{
159-
using var unitOfWork = CreateUnitOfWork();
160-
161-
var (_, posts) = await RepositoryHelper.AddAsyncTestBlogEntitiesWithManyPostsAsync(unitOfWork.Repository<Blog, int>(), 20);
162-
163-
await unitOfWork.CommitAsync();
149+
// Arrange — seed via a separate context so the seeded entities are not in the read
150+
// context's change tracker; the query below genuinely round-trips through the database.
151+
var (_, posts) = await RepositoryHelper.AddAsyncTestBlogEntitiesWithManyPostsAsync(CreateRootDbContext, 20);
164152

165153
var repository = CreateReadRepositoryAsync<BlogPost, int>();
166154

@@ -182,11 +170,9 @@ public async Task GetPageAsync_should_return_a_page_of_entities_without_includes
182170
[Fact]
183171
public async Task GetByIdAsync_should_return_entity_with_includes()
184172
{
185-
using var unitOfWork = CreateUnitOfWork();
186-
187-
var (_, _, blogPost2) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(unitOfWork.Repository<Blog, int>());
188-
189-
await unitOfWork.CommitAsync();
173+
// Arrange — seed via a separate context so the seeded entities are not in the read
174+
// context's change tracker; the query below genuinely round-trips through the database.
175+
var (_, _, blogPost2) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(CreateRootDbContext);
190176

191177
var repository = CreateReadRepositoryAsync<BlogPost, int>();
192178
var blogPost = await repository.GetByIdAsync(blogPost2.Id, query => query.Include(e => e.Tags));
@@ -197,11 +183,9 @@ public async Task GetByIdAsync_should_return_entity_with_includes()
197183
[Fact]
198184
public async Task GetByIdAsync_with_object_key_should_return_entity_with_includes()
199185
{
200-
using var unitOfWork = CreateUnitOfWork();
201-
202-
var (_, _, blogPost2) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(unitOfWork.Repository<Blog, int>());
203-
204-
await unitOfWork.CommitAsync();
186+
// Arrange — seed via a separate context so the seeded entities are not in the read
187+
// context's change tracker; the query below genuinely round-trips through the database.
188+
var (_, _, blogPost2) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(CreateRootDbContext);
205189

206190
var repository = CreateReadRepositoryAsync<BlogPost, int>();
207191
var blogPost = await repository.GetByIdAsync([ blogPost2.Id ]);
@@ -275,18 +259,16 @@ public async Task UpdateAsync_should_throw_if_updated_entity_doesnt_exist()
275259
[Fact]
276260
public async Task FindFirstAsync_should_execute_query_and_return_the_first_hit()
277261
{
278-
using var unitOfWork = CreateUnitOfWork();
279-
280-
var testBlogEntities = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(unitOfWork.Repository<Blog, int>());
281-
282-
await unitOfWork.CommitAsync();
262+
// Arrange — seed via a separate context so the seeded entities are not in the read
263+
// context's change tracker; the query below genuinely round-trips through the database.
264+
var (_, blogPost1, _) = await RepositoryHelper.AddAsyncTestBlogEntitiesAsync(CreateRootDbContext);
283265

284266
var repository = CreateReadWriteRepositoryAsync<BlogPost, int>();
285267
var blogPost = await repository.FindFirstAsync(post => post.Name.Contains("Blog post 1"));
286268

287269
blogPost.Should().NotBeNull();
288270
blogPost.Should()
289-
.BeEquivalentTo(testBlogEntities.blogPost1,
271+
.BeEquivalentTo(blogPost1,
290272
options => options.Excluding(p => p.Categories)
291273
.Excluding(p => p.Tags)
292274
.WithEntityEquivalencyOptions());

tests/Data.GenericRepository/Data.GenericRepository.EFCore.IntegrationTests/ReadWriteRepositoryDeleteByIdTests.cs

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,15 @@ public async Task Delete_by_id_should_remove_entity()
1212
{
1313
const int idToDelete = 10;
1414

15-
using var unitOfWork = CreateUnitOfWork();
16-
var asyncRepo = unitOfWork.Repository<TestEntity, int>();
17-
await asyncRepo.AddAsync(new() { Id = idToDelete, Name = "ToDelete" });
18-
await unitOfWork.CommitAsync();
15+
// Arrange — seed via a separate context so the entity is not tracked by the unit of
16+
// work that performs the delete; the delete then genuinely round-trips through the database.
17+
await using (var seedContext = CreateRootDbContext())
18+
{
19+
await seedContext.TestEntities.AddAsync(new() { Id = idToDelete, Name = "ToDelete" });
20+
await seedContext.SaveChangesAsync();
21+
}
1922

23+
using var unitOfWork = CreateUnitOfWork();
2024
var repository = unitOfWork.Repository<TestEntity, int>();
2125
await repository.DeleteAsync(idToDelete);
2226

@@ -52,11 +56,9 @@ public void GetById_should_return_null_when_entity_does_not_exist()
5256
[Fact]
5357
public async Task GetById_with_onDbSet_should_return_entity()
5458
{
55-
using var unitOfWork = CreateUnitOfWork();
56-
var blogRepository1 = unitOfWork.Repository<Blog, int>();
57-
var (blog, blogPost1, _) = await RepositoryHelper.AddTestBlogEntities(blogRepository1);
58-
59-
await unitOfWork.CommitAsync();
59+
// Arrange — seed via a separate context so the read below re-hydrates from the database
60+
// rather than being served the seeded entities from the read context's change tracker.
61+
var (blog, blogPost1, _) = await RepositoryHelper.AddTestBlogEntitiesAsync(CreateRootDbContext);
6062

6163
var repository = CreateReadRepository<Blog, int>();
6264
var result = repository.GetById(blog.Id, q => q.Include(q => q.BlogPosts).ThenInclude(bp => bp.Tags).Include(q => q.BlogPosts).ThenInclude(bp => bp.Categories));
@@ -83,10 +85,12 @@ public async Task GetById_with_onDbSet_should_return_entity()
8385
[Fact]
8486
public async Task GetById_with_onDbSet_should_return_null_when_filter_excludes_entity()
8587
{
86-
using var unitOfWork = CreateUnitOfWork();
87-
var asyncRepo = unitOfWork.Repository<TestEntity, int>();
88-
await asyncRepo.AddAsync(new() { Id = 1, Name = "Excluded" });
89-
await unitOfWork.CommitAsync();
88+
// Arrange — seed via a separate context so the read genuinely queries the database.
89+
await using (var seedContext = CreateRootDbContext())
90+
{
91+
await seedContext.TestEntities.AddAsync(new() { Id = 1, Name = "Excluded" });
92+
await seedContext.SaveChangesAsync();
93+
}
9094

9195
var repository = CreateReadRepository<TestEntity, int>();
9296
var result = repository.GetById(1, q => q.Where(e => e.Name == "NonExistent"));

tests/Data.GenericRepository/Data.GenericRepository.EFCore.IntegrationTests/RepositoryHelper.cs

Lines changed: 87 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,14 +54,60 @@ public static (Blog, BlogPost, BlogPost) AddTestBlogEntities(IReadWriteRepositor
5454
return (blog, blogPost1, blogPost2);
5555
}
5656

57+
/// <summary>
58+
/// Seeds a blog with two blog posts directly via the <see cref="DbContext" /> and returns the seeded entities.
59+
/// </summary>
60+
/// <remarks>
61+
/// Use this overload in the Arrange phase of an integration test. Seeding through the plain
62+
/// <see cref="DbContext" /> — rather than through a repository — keeps the test's fixture setup
63+
/// independent of the Generic Repository write path, which is itself code under test.
64+
/// </remarks>
65+
/// <param name="dbContext">The <see cref="DbContext" /> to add the blog to.</param>
66+
/// <returns>
67+
/// A task that resolves to a tuple of the seeded <see cref="Blog" /> and the two <see cref="BlogPost" />
68+
/// instances attached to it.
69+
/// </returns>
70+
public static async Task<(Blog, BlogPost, BlogPost)> AddTestBlogEntitiesAsync(DbContext dbContext)
71+
{
72+
var (blog, blogPost1, blogPost2) = EntitiesBuilder.BuildBlogEntity();
73+
74+
await dbContext.AddAsync(blog);
75+
await dbContext.SaveChangesAsync();
76+
77+
return (blog, blogPost1, blogPost2);
78+
}
79+
80+
/// <summary>
81+
/// Seeds a blog with two blog posts via a short-lived <see cref="DbContext" /> obtained from
82+
/// <paramref name="dbContextFactory" /> and returns the seeded entities.
83+
/// </summary>
84+
/// <remarks>
85+
/// The context produced by <paramref name="dbContextFactory" /> is created, used, and disposed
86+
/// inside this method. Pass <c>CreateRootDbContext</c> so the fixture is seeded through a context
87+
/// separate from the one the code under test reads through — this keeps the seeded entities out
88+
/// of the read context's change tracker without the caller managing a context's lifetime or
89+
/// remembering to clear the tracker.
90+
/// </remarks>
91+
/// <param name="dbContextFactory">A factory that produces a new <see cref="DbContext" /> to seed through.</param>
92+
/// <returns>
93+
/// A task that resolves to a tuple of the seeded <see cref="Blog" /> and the two <see cref="BlogPost" />
94+
/// instances attached to it.
95+
/// </returns>
96+
public static async Task<(Blog, BlogPost, BlogPost)> AddTestBlogEntitiesAsync(Func<DbContext> dbContextFactory)
97+
{
98+
await using var dbContext = dbContextFactory();
99+
100+
return await AddTestBlogEntitiesAsync(dbContext);
101+
}
102+
57103
public static IEnumerable<UserIdea> AddTestUserIdeasEntities(IReadWriteRepository<UserIdea, int> userIdeasRepository)
58104
{
59105
var (userIdea1, userIdea2) = EntitiesBuilder.BuildUserIdeaEntities();
60106

61107
userIdeasRepository.Add(userIdea1);
62108
userIdeasRepository.Add(userIdea2);
63109

64-
return new[] { userIdea1, userIdea2 };
110+
return [userIdea1, userIdea2];
65111
}
66112

67113
public static async Task<(Blog blog, BlogPost[] blogPosts)> AddAsyncTestBlogEntitiesWithManyPostsAsync(IReadWriteRepositoryAsync<Blog, int> blogReadWriteRepository,
@@ -206,7 +252,46 @@ public static async Task<IEnumerable<UserIdea>> AddAsyncTestUserIdeasEntitiesAsy
206252
await userIdeasReadWriteRepository.AddAsync(userIdea1);
207253
await userIdeasReadWriteRepository.AddAsync(userIdea2);
208254

209-
return new[] { userIdea1, userIdea2 };
255+
return [userIdea1, userIdea2];
256+
}
257+
258+
/// <summary>
259+
/// Seeds two user-idea entities directly via the <see cref="DbContext" /> and returns them.
260+
/// </summary>
261+
/// <remarks>
262+
/// Use this overload in the Arrange phase of an integration test. Seeding through the plain
263+
/// <see cref="DbContext" /> — rather than through a repository — keeps the test's fixture setup
264+
/// independent of the Generic Repository write path, which is itself code under test.
265+
/// </remarks>
266+
/// <param name="dbContext">The <see cref="DbContext" /> to add the user ideas to.</param>
267+
/// <returns>A task that resolves to the two seeded <see cref="UserIdea" /> entities.</returns>
268+
public static async Task<IEnumerable<UserIdea>> AddAsyncTestUserIdeasEntitiesAsync(DbContext dbContext)
269+
{
270+
var (userIdea1, userIdea2) = EntitiesBuilder.BuildUserIdeaEntities();
271+
272+
await dbContext.AddAsync(userIdea1);
273+
await dbContext.AddAsync(userIdea2);
274+
await dbContext.SaveChangesAsync();
275+
276+
return [userIdea1, userIdea2];
277+
}
278+
279+
/// <summary>
280+
/// Seeds two user-idea entities via a short-lived <see cref="DbContext" /> obtained from
281+
/// <paramref name="dbContextFactory" /> and returns them.
282+
/// </summary>
283+
/// <remarks>
284+
/// The context produced by <paramref name="dbContextFactory" /> is created, used, and disposed
285+
/// inside this method. Pass <c>CreateRootDbContext</c> to seed through a context separate from
286+
/// the one the code under test reads through.
287+
/// </remarks>
288+
/// <param name="dbContextFactory">A factory that produces a new <see cref="DbContext" /> to seed through.</param>
289+
/// <returns>A task that resolves to the two seeded <see cref="UserIdea" /> entities.</returns>
290+
public static async Task<IEnumerable<UserIdea>> AddAsyncTestUserIdeasEntitiesAsync(Func<DbContext> dbContextFactory)
291+
{
292+
await using var dbContext = dbContextFactory();
293+
294+
return await AddAsyncTestUserIdeasEntitiesAsync(dbContext);
210295
}
211296

212297
public static async Task<BlogPostTag[]> AddBlogPostTagsAsync(IReadWriteRepositoryAsync<BlogPostTag, int> repository, int tagCount)

0 commit comments

Comments
 (0)