Skip to content

Commit 79cc900

Browse files
committed
Refactor paged results extension and repository usage; update test verification and project references
- Comment out GetPagedResultsAsync extension using custom SQL for total count; suppress with pragma - Update RepositoryBase to use simplified GetPagedResultsAsync signature without DbContext parameter - Adjust RepositoryBaseTests to verify updates directly via DbContext for accuracy and clarity - Add ZeidLab.ToolBox.EasyPersistence.EFCoreSqlClr.dll as a None item in test project for output copying - Change EfCoreSqlClr.csproj to use PackageReference for Microsoft.SqlServer.Server - Minor cleanup in EFCore.csproj NuGet packaging target - Use ArgumentNullException.ThrowIfNull in SqlClrHelperExtensions for null checks
1 parent 44d60c5 commit 79cc900

7 files changed

Lines changed: 78 additions & 62 deletions

File tree

src/EFCore/EFCore.csproj

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -111,18 +111,20 @@
111111

112112
<Target Name="PackEfCoreSqlClrDll" AfterTargets="Build">
113113
<!-- Copy the EfCoreSqlClr.dll to the output directory with retry logic -->
114-
<Copy
115-
SourceFiles="..\EfCoreSqlClr\bin\Release\net48\ZeidLab.ToolBox.EasyPersistence.EFCoreSqlClr.dll"
116-
DestinationFolder="$(OutputPath)"
117-
SkipUnchangedFiles="true"
118-
ContinueOnError="true"
119-
RetryDelayMilliseconds="500"
120-
Retries="5"/>
114+
<Copy
115+
SourceFiles="..\EfCoreSqlClr\bin\Release\net48\ZeidLab.ToolBox.EasyPersistence.EFCoreSqlClr.dll"
116+
DestinationFolder="$(OutputPath)"
117+
SkipUnchangedFiles="true"
118+
ContinueOnError="true"
119+
RetryDelayMilliseconds="500"
120+
Retries="5"/>
121121

122122

123123
<!-- Include the EasyPersistence.EfCoreSqlClr.dll in the NuGet package -->
124124
<ItemGroup>
125-
<None Include="$(OutputPath)\ZeidLab.ToolBox.EasyPersistence.EFCoreSqlClr.dll" Pack="true" PackagePath="lib\net48\"/>
125+
<None Include="..\EfCoreSqlClr\bin\Release\net48\ZeidLab.ToolBox.EasyPersistence.EFCoreSqlClr.dll"
126+
Pack="true"
127+
PackagePath="lib\net48\" />
126128
</ItemGroup>
127129
</Target>
128130
</Project>

src/EFCore/Extensions/HelperExtensions.cs

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -60,42 +60,44 @@ public static async Task<PagedResult<TEntity>> GetPagedResultsAsync<TEntity>(thi
6060
return new PagedResult<TEntity>(items, itemsCount);
6161
}
6262

63-
/// <summary>
64-
/// Returns a paged result for the specified query using a custom SQL query for total count.
65-
/// </summary>
66-
/// <typeparam name="TEntity">The type of the entity.</typeparam>
67-
/// <typeparam name="TDbContext">The type of the DbContext.</typeparam>
68-
/// <param name="query">The source query.</param>
69-
/// <param name="dbContext">The database context to execute the query.</param>
70-
/// <param name="page">The zero-based page index.</param>
71-
/// <param name="pageSize">The number of items per page.</param>
72-
/// <returns>A <see cref="PagedResult{TEntity}"/> containing the items and total count.</returns>
73-
/// <example>
74-
/// <code><![CDATA[
75-
/// var paged = await dbContext.People.GetPagedResultsAsync(dbContext, 0, 10);
76-
/// ]]></code>
77-
/// </example>
78-
public static async Task<PagedResult<TEntity>> GetPagedResultsAsync<TEntity, TDbContext>(
79-
this IQueryable<TEntity> query,
80-
TDbContext dbContext, int page, int pageSize) where TEntity : class where TDbContext : DbContext
81-
{
82-
// Generate SQL that includes COUNT(*) OVER() to get total count in single query
83-
var sql = query.ToQueryString();
84-
var countedSql = $"SELECT *, COUNT(*) OVER() AS TotalCount FROM ({sql}) AS CountedQuery " +
85-
$"ORDER BY (SELECT NULL) OFFSET {(page * pageSize).ToString(CultureInfo.InvariantCulture)}" +
86-
$" ROWS FETCH NEXT {pageSize.ToString(CultureInfo.InvariantCulture)} ROWS ONLY";
87-
88-
// Execute the query
89-
var result = await dbContext.Set<TEntity>()
90-
.FromSqlRaw(countedSql)
91-
.AsNoTracking()
92-
.ToListAsync()
93-
.ConfigureAwait(false);
94-
95-
// Get total count from the first row (or 0 if no results)
96-
var totalCount = result.Any()
97-
? (long)(result[0].GetType().GetProperty("TotalCount")?.GetValue(result[0], null) ?? 0)
98-
: 0;
99-
return new PagedResult<TEntity>(result, totalCount);
100-
}
101-
}
63+
#pragma warning disable S125
64+
// /// <summary>
65+
// /// Returns a paged result for the specified query using a custom SQL query for total count.
66+
// /// </summary>
67+
// /// <typeparam name="TEntity">The type of the entity.</typeparam>
68+
// /// <typeparam name="TDbContext">The type of the DbContext.</typeparam>
69+
// /// <param name="query">The source query.</param>
70+
// /// <param name="dbContext">The database context to execute the query.</param>
71+
// /// <param name="page">The zero-based page index.</param>
72+
// /// <param name="pageSize">The number of items per page.</param>
73+
// /// <returns>A <see cref="PagedResult{TEntity}"/> containing the items and total count.</returns>
74+
// /// <example>
75+
// /// <code><![CDATA[
76+
// /// var paged = await dbContext.People.GetPagedResultsAsync(dbContext, 0, 10);
77+
// /// ]]></code>
78+
// /// </example>
79+
// public static async Task<PagedResult<TEntity>> GetPagedResultsAsync<TEntity, TDbContext>(
80+
// this IQueryable<TEntity> query,
81+
// TDbContext dbContext, int page, int pageSize) where TEntity : class where TDbContext : DbContext
82+
// {
83+
// // Generate SQL that includes COUNT(*) OVER() to get total count in single query
84+
// var sql = query.ToQueryString();
85+
// var countedSql = $"SELECT *, COUNT(*) OVER() AS TotalCount FROM ({sql}) AS CountedQuery " +
86+
// $"ORDER BY (SELECT NULL) OFFSET {(page * pageSize).ToString(CultureInfo.InvariantCulture)}" +
87+
// $" ROWS FETCH NEXT {pageSize.ToString(CultureInfo.InvariantCulture)} ROWS ONLY";
88+
//
89+
// // Execute the query
90+
// var result = await dbContext.Set<TEntity>()
91+
// .FromSqlRaw(countedSql)
92+
// .AsNoTracking()
93+
// .Select(x =>
94+
// new { Item = x, TotalCount = EF.Property<int>(x, "TotalCount") })
95+
// .ToListAsync()
96+
// .ConfigureAwait(false);
97+
//
98+
// // Get total count from the first row (or 0 if no results)
99+
// long totalCount = result.Count != 0 ? result[0].TotalCount : 0;
100+
// return new PagedResult<TEntity>(result.ConvertAll(x => x.Item), totalCount);
101+
// }
102+
#pragma warning restore S125
103+
}

src/EFCore/Extensions/SqlClrHelperExtensions.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ public static async Task InitializeSqlClrAsync(
2020
this DbContext context,
2121
CancellationToken cancellationToken = default)
2222
{
23-
if (context == null)
24-
throw new ArgumentNullException(nameof(context));
23+
ArgumentNullException.ThrowIfNull(context);
2524
const string assemblyName = "EFCoreSqlClr";
2625
var assemblyPath = Path.Combine(AppContext.BaseDirectory, "ZeidLab.ToolBox.EasyPersistence.EFCoreSqlClr.dll");
2726

src/EFCore/Services/RepositoryBase.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,14 @@ public Task<PagedResult<TEntity>> GetPagedResultsAsync(Expression<Func<TEntity,
9595
{
9696
return _context.Set<TEntity>()
9797
.Where(predicate)
98-
.GetPagedResultsAsync(_context,page, pageSize);
98+
.GetPagedResultsAsync(page, pageSize);
9999
}
100100

101101
/// <inheritdoc/>
102102
public Task<PagedResult<TEntity>> GetPagedResultsAsync(int page, int pageSize)
103103
{
104104
return _context.Set<TEntity>()
105-
.GetPagedResultsAsync(_context,page, pageSize);
105+
.GetPagedResultsAsync(page, pageSize);
106106
}
107107

108108
/// <inheritdoc/>
@@ -112,7 +112,7 @@ public Task<PagedResult<TEntity>> SearchAsync(string searchTerm,
112112
{
113113
return _context.Set<TEntity>().Where(predicate)
114114
.ApplySearch(searchTerm, fieldsToSearch)
115-
.GetPagedResultsAsync(_context,page, pageSize);
115+
.GetPagedResultsAsync(page, pageSize);
116116
}
117117

118118
/// <inheritdoc/>
@@ -121,7 +121,7 @@ public Task<PagedResult<TEntity>> SearchAsync(string searchTerm, int page = 0, i
121121
{
122122
return _context.Set<TEntity>()
123123
.ApplySearch(searchTerm, fieldsToSearch)
124-
.GetPagedResultsAsync(_context,page, pageSize);
124+
.GetPagedResultsAsync(page, pageSize);
125125
}
126126

127127
/// <inheritdoc/>

src/EfCoreSqlClr/EfCoreSqlClr.csproj

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22
<PropertyGroup>
3-
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
43
<OutputType>Library</OutputType>
54
<TargetFramework>net48</TargetFramework>
6-
</PropertyGroup>
5+
</PropertyGroup>
76
<ItemGroup Label="Test Assembly Attributes">
87
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
98
<_Parameter1>$(AssemblyName).Test.UI</_Parameter1>
@@ -20,7 +19,7 @@
2019
</ItemGroup>
2120

2221
<ItemGroup>
23-
<Reference Include="Microsoft.SqlServer.Server" Version="1.0.0"/>
22+
<PackageReference Include="Microsoft.SqlServer.Server"/>
2423
</ItemGroup>
2524

2625
<Import Project="PostBuild.targets"/>

tests/EFCore.Test.Integrations/EFCore.Test.Integrations.csproj

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
<ProjectReference Include="..\..\src\EFCore\EFCore.csproj" />
1515
<ProjectReference Include="..\TestHelpers\TestHelpers.csproj" />
1616
</ItemGroup>
17-
17+
<ItemGroup>
18+
<None Include="..\..\src\EfCoreSqlClr\bin\Release\net48\ZeidLab.ToolBox.EasyPersistence.EFCoreSqlClr.dll">
19+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
20+
</None>
21+
</ItemGroup>
1822
<ItemGroup>
1923
<None Update="xunit.runner.json">
2024
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>

tests/EFCore.Test.Integrations/RepositoryBaseTests.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,10 @@ public async Task UpdatePropertyAsync_WithSingleProperty_ShouldUpdateMatchingEnt
278278
updatedRows.Should().Be(2); // Two rows should be updated
279279

280280
// Verify update in database
281-
var updatedUsers = await testUnitOfWork.Users.FindAllAsync(u => u.LastName == "Smith-Updated");
281+
var updatedUsers = await dbContext.Users
282+
.AsNoTracking()
283+
.Where(u => u.LastName == "Smith-Updated")
284+
.ToListAsync();
282285
updatedUsers.Count.Should().Be(2);
283286
updatedUsers.All(u => u.LastName == "Smith-Updated").Should().BeTrue();
284287
}
@@ -312,9 +315,13 @@ public async Task UpdatePropertyAsync_WithMultipleProperties_ShouldUpdateMatchin
312315
updatedRows.Should().Be(2); // Two rows should be updated
313316

314317
// Verify update in database
315-
var updatedUsers = await testUnitOfWork.Users.FindAllAsync(u => u.LastName == "Updated-LastName");
318+
var updatedUsers =
319+
await dbContext.Users
320+
.AsNoTracking()
321+
.Where(u => u.LastName == "Smith-Updated")
322+
.ToListAsync();
316323
updatedUsers.Count.Should().Be(2);
317-
updatedUsers.All(u => u.FirstName == "Updated-FirstName" && u.LastName == "Updated-LastName").Should().BeTrue();
324+
updatedUsers.All(u => u.FirstName == "Updated-FirstName" && u.LastName == "Smith-Updated").Should().BeTrue();
318325
}
319326

320327
[Fact]
@@ -346,8 +353,10 @@ public async Task UpdatePropertyAsync_WithDifferentPropertyTypes_ShouldUpdateMat
346353
updatedRows.Should().Be(2); // Two rows should be updated
347354

348355
// Verify update in database
349-
var updatedUsers = await testUnitOfWork.Users.FindAllAsync(u
350-
=> u.LastName == "Smith");
356+
var updatedUsers = await dbContext.Users
357+
.AsNoTracking()
358+
.Where(u
359+
=> u.LastName == "Smith").ToListAsync();
351360
updatedUsers.Count.Should().Be(2);
352361
updatedUsers.All(u => u.DateOfBirth == newDate).Should().BeTrue();
353362
}
@@ -423,6 +432,7 @@ public async Task RollbackTransactionAsync_ShouldDiscardChanges()
423432
var retrievedUser = await testUnitOfWork.Users.GetByIdAsync(user.Id);
424433
retrievedUser.Should().BeNull();
425434
}
435+
426436
public async Task InitializeAsync()
427437
{
428438
await _dbGenerator.MakeSureIsRunningAsync();

0 commit comments

Comments
 (0)