Skip to content

Commit 8b73a86

Browse files
committed
TD-2186 - Code modified to limit 250 row fetch from database.
1 parent 9199eab commit 8b73a86

File tree

5 files changed

+127
-21
lines changed

5 files changed

+127
-21
lines changed

DigitalLearningSolutions.Data/DataServices/CourseDataService.cs

Lines changed: 76 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ namespace DigitalLearningSolutions.Data.DataServices
1111
using System.Collections.Generic;
1212
using System.Data;
1313
using System.Linq;
14+
using System.Threading.Tasks;
1415

1516
public interface ICourseDataService
1617
{
@@ -96,7 +97,10 @@ int diagCompletionThreshold
9697

9798
IEnumerable<CourseDelegateForExport> GetDelegatesOnCourseForExport(int customisationId, int centreId);
9899

99-
IEnumerable<CourseDelegateForExport> GetCourseDelegatesForExport(string searchString, string sortBy, string sortDirection,
100+
int GetCourseDelegatesCountForExport(string searchString, string sortBy, string sortDirection,
101+
int customisationId, int centreId, bool? isDelegateActive, bool? isProgressLocked, bool? removed, bool? hasCompleted, string? answer1, string? answer2, string? answer3);
102+
103+
Task<IEnumerable<CourseDelegateForExport>> GetCourseDelegatesForExport(string searchString, int offSet, int itemsPerPage, string sortBy, string sortDirection,
100104
int customisationId, int centreId, bool? isDelegateActive, bool? isProgressLocked, bool? removed, bool? hasCompleted, string? answer1, string? answer2, string? answer3);
101105

102106
int EnrolOnActivitySelfAssessment(int selfAssessmentId, int candidateId, int supervisorId, string adminEmail,
@@ -1348,7 +1352,75 @@ FROM DelegateAccounts AS da
13481352
);
13491353
}
13501354

1351-
public IEnumerable<CourseDelegateForExport> GetCourseDelegatesForExport(string searchString, string sortBy, string sortDirection,
1355+
public int GetCourseDelegatesCountForExport(string searchString, string sortBy, string sortDirection,
1356+
int customisationId, int centreId, bool? isDelegateActive, bool? isProgressLocked, bool? removed, bool? hasCompleted, string? answer1, string? answer2, string? answer3)
1357+
{
1358+
1359+
var fromTableQuery = $@" FROM Customisations cu WITH (NOLOCK)
1360+
INNER JOIN Applications AS ap WITH (NOLOCK) ON ap.ApplicationID = cu.ApplicationID
1361+
INNER JOIN Progress AS pr WITH (NOLOCK) ON pr.CustomisationID = cu.CustomisationID
1362+
LEFT OUTER JOIN AdminAccounts AS aaSupervisor WITH (NOLOCK) ON aaSupervisor.ID = pr.SupervisorAdminId
1363+
LEFT OUTER JOIN Users AS uSupervisor WITH (NOLOCK) ON uSupervisor.ID = aaSupervisor.UserID
1364+
LEFT OUTER JOIN AdminAccounts AS aaEnrolledBy WITH (NOLOCK) ON aaEnrolledBy.ID = pr.EnrolledByAdminID
1365+
LEFT OUTER JOIN Users AS uEnrolledBy WITH (NOLOCK) ON uEnrolledBy.ID = aaEnrolledBy.UserID
1366+
INNER JOIN DelegateAccounts AS da WITH (NOLOCK) ON da.ID = pr.CandidateID
1367+
INNER JOIN Users AS u WITH (NOLOCK) ON u.ID = da.UserID
1368+
LEFT JOIN UserCentreDetails AS ucd WITH (NOLOCK) ON ucd.UserID = da.UserID AND ucd.centreID = da.CentreID
1369+
1370+
WHERE (cu.CentreID = @centreId OR
1371+
(cu.AllCentres = 1 AND
1372+
EXISTS (SELECT CentreApplicationID
1373+
FROM CentreApplications cap
1374+
WHERE cap.ApplicationID = cu.ApplicationID AND
1375+
cap.CentreID = @centreID AND
1376+
cap.Active = 1)))
1377+
AND da.CentreID = @centreId
1378+
AND pr.CustomisationID = @customisationId
1379+
AND ap.DefaultContentTypeID <> 4
1380+
1381+
AND ( u.FirstName + ' ' + u.LastName + ' ' + COALESCE(ucd.Email, u.PrimaryEmail) + ' ' + COALESCE(CandidateNumber, '') LIKE N'%' + @searchString + N'%')
1382+
AND ((@isDelegateActive IS NULL) OR (@isDelegateActive = 1 AND (da.Active = 1)) OR (@isDelegateActive = 0 AND (da.Active = 0)))
1383+
AND ((@isProgressLocked IS NULL) OR (@isProgressLocked = 1 AND (pr.PLLocked = 1)) OR (@isProgressLocked = 0 AND (pr.PLLocked = 0)))
1384+
AND ((@removed IS NULL) OR (@removed = 1 AND (pr.RemovedDate IS NOT NULL)) OR (@removed = 0 AND (pr.RemovedDate IS NULL)))
1385+
AND ((@hasCompleted IS NULL) OR (@hasCompleted = 1 AND pr.Completed IS NOT NULL) OR (@hasCompleted = 0 AND pr.Completed IS NULL))
1386+
1387+
AND ((@answer1 IS NULL) OR ((@answer1 = 'No option selected' OR @answer1 = 'FREETEXTBLANKVALUE') AND (pr.Answer1 IS NULL OR TRIM(pr.Answer1) = ''))
1388+
OR (@answer1 = 'FREETEXTNOTBLANKVALUE' AND (pr.Answer1 IS NOT NULL OR pr.Answer1 = @answer1)))
1389+
1390+
AND ((@answer2 IS NULL) OR ((@answer2 = 'No option selected' OR @answer2 = 'FREETEXTBLANKVALUE') AND (pr.Answer2 IS NULL OR TRIM(pr.Answer2) = ''))
1391+
OR (@answer2 = 'FREETEXTNOTBLANKVALUE' AND (pr.Answer2 IS NOT NULL OR pr.Answer2 = @answer2)))
1392+
1393+
AND ((@answer3 IS NULL) OR ((@answer3 = 'No option selected' OR @answer3 = 'FREETEXTBLANKVALUE') AND (pr.Answer3 IS NULL OR TRIM(pr.Answer3) = ''))
1394+
OR (@answer3 = 'FREETEXTNOTBLANKVALUE' AND (pr.Answer3 IS NOT NULL OR pr.Answer3 = @answer3)))
1395+
1396+
AND COALESCE(ucd.Email, u.PrimaryEmail) LIKE '%_@_%.__%'";
1397+
1398+
1399+
var mainSql = "SELECT COUNT(*) AS TotalRecords " + fromTableQuery;
1400+
1401+
return connection.ExecuteScalar<int>(
1402+
mainSql,
1403+
new
1404+
{
1405+
searchString,
1406+
sortBy,
1407+
sortDirection,
1408+
customisationId,
1409+
centreId,
1410+
isDelegateActive,
1411+
isProgressLocked,
1412+
removed,
1413+
hasCompleted,
1414+
answer1,
1415+
answer2,
1416+
answer3
1417+
},
1418+
commandTimeout: 3000
1419+
);
1420+
}
1421+
1422+
1423+
public async Task<IEnumerable<CourseDelegateForExport>> GetCourseDelegatesForExport(string searchString, int offSet, int itemsPerPage, string sortBy, string sortDirection,
13521424
int customisationId, int centreId, bool? isDelegateActive, bool? isProgressLocked, bool? removed, bool? hasCompleted, string? answer1, string? answer2, string? answer3)
13531425
{
13541426

@@ -1437,6 +1509,8 @@ AND ap.DefaultContentTypeID <> 4
14371509
else
14381510
orderBy = " ORDER BY " + sortBy + sortOrder;
14391511

1512+
orderBy += " OFFSET " + offSet + " ROWS FETCH NEXT " + itemsPerPage + " ROWS ONLY ";
1513+
14401514

14411515
var mainSql = selectColumnQuery + fromTableQuery + orderBy;
14421516

DigitalLearningSolutions.Web.Tests/Controllers/TrackingSystem/Delegates/CourseDelegatesControllerTests.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
using Microsoft.AspNetCore.Http;
1818
using Microsoft.AspNetCore.Mvc;
1919
using Microsoft.AspNetCore.Mvc.ViewFeatures;
20+
using Microsoft.Extensions.Configuration;
2021
using NUnit.Framework;
2122

2223
public class CourseDelegatesControllerTests
@@ -26,18 +27,21 @@ public class CourseDelegatesControllerTests
2627
private ICourseDelegatesDownloadFileService courseDelegatesDownloadFileService = null!;
2728
private ICourseDelegatesService courseDelegatesService = null!;
2829
private IPaginateService paginateService = null!;
30+
private IConfiguration configuration = null!;
2931

3032
[SetUp]
3133
public void SetUp()
3234
{
3335
courseDelegatesService = A.Fake<ICourseDelegatesService>();
3436
courseDelegatesDownloadFileService = A.Fake<ICourseDelegatesDownloadFileService>();
3537
paginateService = A.Fake<IPaginateService>();
38+
configuration = A.Fake<IConfiguration>();
3639

3740
controller = new CourseDelegatesController(
3841
courseDelegatesService,
3942
courseDelegatesDownloadFileService,
40-
paginateService
43+
paginateService,
44+
configuration
4145
)
4246
.WithDefaultContext()
4347
.WithMockHttpContextSession()
@@ -129,7 +133,8 @@ public void Index_should_default_to_Active_filter()
129133
var courseDelegatesController = new CourseDelegatesController(
130134
courseDelegatesService,
131135
courseDelegatesDownloadFileService,
132-
paginateService
136+
paginateService,
137+
configuration
133138
)
134139
.WithMockHttpContext(httpRequest, cookieName, cookieValue, httpResponse)
135140
.WithMockUser(true, UserCentreId)

DigitalLearningSolutions.Web.Tests/Services/CourseDelegatesDownloadFileServiceTests.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,17 @@
55
using System.Globalization;
66
using System.IO;
77
using System.Linq;
8+
using System.Threading.Tasks;
89
using ClosedXML.Excel;
910
using DigitalLearningSolutions.Data.DataServices;
11+
using DigitalLearningSolutions.Data.Extensions;
1012
using DigitalLearningSolutions.Data.Models.CourseDelegates;
1113
using DigitalLearningSolutions.Data.Models.Courses;
1214
using DigitalLearningSolutions.Data.Models.CustomPrompts;
1315
using DigitalLearningSolutions.Data.Tests.TestHelpers;
1416
using DigitalLearningSolutions.Web.Services;
1517
using FakeItEasy;
18+
using Microsoft.Extensions.Configuration;
1619
using NUnit.Framework;
1720

1821
public class CourseDelegatesDownloadFileServiceTests
@@ -190,17 +193,18 @@ public void Setup()
190193
courseDataService = A.Fake<ICourseDataService>();
191194
registrationPromptsService = A.Fake<ICentreRegistrationPromptsService>();
192195
courseService = A.Fake<ICourseService>();
193-
196+
194197
courseDelegatesDownloadFileService = new CourseDelegatesDownloadFileService(
195198
courseDataService,
196199
courseAdminFieldsService,
197200
registrationPromptsService,
198201
courseService
199202
);
203+
200204
}
201205

202206
[Test]
203-
public void GetDelegateDownloadFileForCourse_returns_expected_excel_data()
207+
public async Task GetDelegateDownloadFileForCourse_returns_expected_excel_data()
204208
{
205209
// Given
206210
const int customisationId = 1;
@@ -209,7 +213,11 @@ public void GetDelegateDownloadFileForCourse_returns_expected_excel_data()
209213
TestContext.CurrentContext.TestDirectory + CourseDelegateExportCurrentDataDownloadRelativeFilePath
210214
);
211215

212-
A.CallTo(() => courseDataService.GetCourseDelegatesForExport(string.Empty, "SearchableName", "Ascending",
216+
A.CallTo(() => courseDataService.GetCourseDelegatesCountForExport(string.Empty,"SearchableName", "Ascending",
217+
customisationId, centreId, null, null, null, null, null, null, null))
218+
.Returns(3);
219+
220+
A.CallTo(() => courseDataService.GetCourseDelegatesForExport(string.Empty,0,250, "SearchableName", "Ascending",
213221
customisationId, centreId, null, null, null, null, null, null, null))
214222
.Returns(courseDelegates.Where(c => c.ApplicationName == "Course One"));
215223

@@ -233,7 +241,7 @@ public void GetDelegateDownloadFileForCourse_returns_expected_excel_data()
233241

234242
// When
235243

236-
var resultBytes = courseDelegatesDownloadFileService.GetCourseDelegateDownloadFileForCourse(string.Empty, "SearchableName", "Ascending",
244+
var resultBytes = await courseDelegatesDownloadFileService.GetCourseDelegateDownloadFileForCourse(string.Empty,0,250, "SearchableName", "Ascending",
237245
customisationId, centreId, null, null, null, null, null, null, null
238246
);
239247

DigitalLearningSolutions.Web/Controllers/TrackingSystem/Delegates/CourseDelegatesController.cs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
using DigitalLearningSolutions.Web.ViewModels.TrackingSystem.Delegates.CourseDelegates;
1313
using Microsoft.AspNetCore.Authorization;
1414
using Microsoft.AspNetCore.Mvc;
15+
using Microsoft.Extensions.Configuration;
1516
using Microsoft.FeatureManagement.Mvc;
1617
using System;
1718
using System.Linq;
19+
using System.Threading.Tasks;
1820

1921
[FeatureGate(FeatureFlags.RefactoredTrackingSystem)]
2022
[Authorize(Policy = CustomPolicies.UserCentreAdmin)]
@@ -27,16 +29,19 @@ public class CourseDelegatesController : Controller
2729
private readonly ICourseDelegatesDownloadFileService courseDelegatesDownloadFileService;
2830
private readonly ICourseDelegatesService courseDelegatesService;
2931
private readonly IPaginateService paginateService;
32+
private readonly IConfiguration configuration;
3033

3134
public CourseDelegatesController(
3235
ICourseDelegatesService courseDelegatesService,
3336
ICourseDelegatesDownloadFileService courseDelegatesDownloadFileService,
34-
IPaginateService paginateService
37+
IPaginateService paginateService,
38+
IConfiguration configuration
3539
)
3640
{
3741
this.courseDelegatesService = courseDelegatesService;
3842
this.courseDelegatesDownloadFileService = courseDelegatesDownloadFileService;
3943
this.paginateService = paginateService;
44+
this.configuration = configuration;
4045
}
4146

4247
[NoCaching]
@@ -195,7 +200,7 @@ public IActionResult Index(
195200

196201
[ServiceFilter(typeof(VerifyAdminUserCanViewCourse))]
197202
[Route("DownloadCurrent/{customisationId:int}")]
198-
public IActionResult DownloadCurrent(
203+
public async Task<IActionResult> DownloadCurrent(
199204
int customisationId,
200205
string? searchString = null,
201206
string? sortBy = null,
@@ -254,16 +259,15 @@ public IActionResult DownloadCurrent(
254259
}
255260
}
256261
}
257-
258-
var content = courseDelegatesDownloadFileService.GetCourseDelegateDownloadFileForCourse(searchString ?? string.Empty, sortBy, sortDirection,
262+
var itemsPerPage = Data.Extensions.ConfigurationExtensions.GetExportQueryRowLimit(configuration);
263+
var content = await courseDelegatesDownloadFileService.GetCourseDelegateDownloadFileForCourse(searchString ?? string.Empty, 0, itemsPerPage, sortBy, sortDirection,
259264
customisationId, centreId, isDelegateActive, isProgressLocked, removed, hasCompleted, answer1, answer2, answer3
260265
);
261266

262267
const string fileName = "Digital Learning Solutions Course Delegates.xlsx";
263-
return File(
264-
content,
265-
FileHelper.GetContentTypeFromFileName(fileName),
266-
fileName
268+
return File(content,
269+
FileHelper.GetContentTypeFromFileName(fileName),
270+
fileName
267271
);
268272
}
269273
}

DigitalLearningSolutions.Web/Services/CourseDelegatesDownloadFileService.cs

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using System.Data;
55
using System.IO;
66
using System.Linq;
7+
using System.Threading.Tasks;
78
using ClosedXML.Excel;
89
using DigitalLearningSolutions.Data.DataServices;
910
using DigitalLearningSolutions.Data.Helpers;
@@ -13,7 +14,7 @@
1314

1415
public interface ICourseDelegatesDownloadFileService
1516
{
16-
public byte[] GetCourseDelegateDownloadFileForCourse(string searchString, string sortBy, string sortDirection,
17+
public Task<byte[]> GetCourseDelegateDownloadFileForCourse(string searchString, int offSet, int itemsPerPage, string sortBy, string sortDirection,
1718
int customisationId, int centreId, bool? isDelegateActive, bool? isProgressLocked, bool? removed, bool? hasCompleted, string? answer1, string? answer2, string? answer3
1819
);
1920

@@ -68,7 +69,7 @@ ICourseService courseService
6869
this.courseService = courseService;
6970
}
7071

71-
public byte[] GetCourseDelegateDownloadFileForCourse(string searchString, string sortBy, string sortDirection,
72+
public async Task<byte[]> GetCourseDelegateDownloadFileForCourse(string searchString, int offSet, int itemsPerPage, string sortBy, string sortDirection,
7273
int customisationId, int centreId, bool? isDelegateActive, bool? isProgressLocked, bool? removed, bool? hasCompleted, string? answer1, string? answer2, string? answer3
7374
)
7475
{
@@ -78,9 +79,23 @@ public byte[] GetCourseDelegateDownloadFileForCourse(string searchString, string
7879

7980
var customRegistrationPrompts = registrationPromptsService.GetCentreRegistrationPromptsByCentreId(centreId);
8081

81-
var courseDelegates = courseDataService.GetCourseDelegatesForExport(searchString ?? string.Empty, sortBy, sortDirection,
82-
customisationId, centreId, isDelegateActive, isProgressLocked, removed, hasCompleted, answer1, answer2, answer3)
83-
.ToList();
82+
int resultCount = courseDataService.GetCourseDelegatesCountForExport(searchString ?? string.Empty, sortBy, sortDirection,
83+
customisationId, centreId, isDelegateActive, isProgressLocked, removed, hasCompleted, answer1, answer2, answer3);
84+
85+
86+
int page = 1;
87+
int totalPages = (int)(resultCount / itemsPerPage) + ((resultCount % itemsPerPage) > 0 ? 1 : 0);
88+
89+
List<CourseDelegateForExport> courseDelegates = new List<CourseDelegateForExport>();
90+
91+
while (totalPages >= page)
92+
{
93+
offSet = ((page - 1) * itemsPerPage);
94+
95+
courseDelegates.AddRange(await this.courseDataService.GetCourseDelegatesForExport(searchString ?? string.Empty, offSet, itemsPerPage, sortBy, sortDirection,
96+
customisationId, centreId, isDelegateActive, isProgressLocked, removed, hasCompleted, answer1, answer2, answer3));
97+
page++;
98+
}
8499

85100
PopulateCourseDelegatesSheetForCourse(
86101
workbook,

0 commit comments

Comments
 (0)