Refactor collection initializers to use C# 12 collection expressions
This commit updates various files across the Core and WebApp projects to replace traditional collection initializers with C# 12 collection expressions. Changes include modifications to EventAssignment.cs, TeamScheduler_DecisionTree.cs, CareerField.cs, EventDefinition.cs, and several components in the WebApp. These updates enhance code readability and maintainability by adhering to modern C# syntax standards.
This commit is contained in:
@@ -99,7 +99,7 @@
|
||||
// Load teams for all event definitions
|
||||
var teamsByEventId = await EventOccurrenceService.GetTeamsByEventDefinitionIdsAsync(eventDefinitionIds);
|
||||
|
||||
var items = new List<CalendarEventItem>();
|
||||
List<CalendarEventItem> items = [];
|
||||
foreach (var occ in eventOccurrences)
|
||||
{
|
||||
try
|
||||
@@ -112,7 +112,7 @@
|
||||
// Get student first names for this event definition
|
||||
var studentFirstNames = occ.EventDefinition != null
|
||||
? StudentFirstNames(occ.EventDefinition, teamsByEventId)
|
||||
: new List<string>();
|
||||
: [];
|
||||
|
||||
var calendarItem = new CalendarEventItem(occ, studentFirstNames);
|
||||
items.Add(calendarItem);
|
||||
@@ -135,7 +135,7 @@
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.LogError(ex, "Error loading calendar events");
|
||||
_calendarItems = new List<CalendarEventItem>();
|
||||
_calendarItems = [];
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -145,7 +145,7 @@
|
||||
|
||||
private static List<string> StudentFirstNames(EventDefinition ed, Dictionary<int, List<Team>> teamsByEventId)
|
||||
{
|
||||
var studentFirstNames = new List<string>();
|
||||
List<string> studentFirstNames = [];
|
||||
if (ed?.Id == null || !teamsByEventId.TryGetValue(ed.Id, out var teams)) return studentFirstNames;
|
||||
|
||||
// Get all unique student first names from all teams for this event
|
||||
@@ -220,7 +220,7 @@
|
||||
|
||||
private string GetEventTooltip(CalendarEventItem item)
|
||||
{
|
||||
var parts = new List<string>();
|
||||
List<string> parts = [];
|
||||
|
||||
if (!string.IsNullOrEmpty(item.EventDefinition?.Name))
|
||||
{
|
||||
|
||||
@@ -118,7 +118,7 @@ else
|
||||
{
|
||||
if (!_fieldIdToCareers.ContainsKey(field.Id))
|
||||
{
|
||||
_fieldIdToCareers[field.Id] = new List<string>();
|
||||
_fieldIdToCareers[field.Id] = [];
|
||||
}
|
||||
// Add unique career names for this field
|
||||
foreach (var career in evt.RelatedCareers)
|
||||
@@ -153,8 +153,8 @@ else
|
||||
|
||||
private NetworkData GenerateNetworkData(List<EventDefinition> events)
|
||||
{
|
||||
var nodes = new List<Node>();
|
||||
var edges = new List<Edge>();
|
||||
List<Node> nodes = [];
|
||||
List<Edge> edges = [];
|
||||
|
||||
// Dictionary to track node IDs (to avoid duplicates)
|
||||
var eventNodeIds = new Dictionary<int, string>();
|
||||
@@ -284,7 +284,7 @@ else
|
||||
Title = field.Name,
|
||||
Description = field.Description,
|
||||
IsCareerField = true,
|
||||
Careers = careers?.ToList() ?? new List<string>()
|
||||
Careers = careers?.ToList() ?? []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@page "/events"
|
||||
@attribute [Authorize]
|
||||
@implements IAsyncDisposable
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using WebApp.Models
|
||||
@using WebApp.Components.Shared.Components
|
||||
@@ -74,16 +75,32 @@
|
||||
@code {
|
||||
MudDataGrid<EventDefinition> _dataGrid = null!;
|
||||
private bool _isLoading = true;
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private bool _isDisposed = false;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
private async Task<GridData<EventDefinition>> ServerReload(GridState<EventDefinition> state)
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return new GridData<EventDefinition> { TotalItems = 0, Items = [] };
|
||||
}
|
||||
|
||||
_isLoading = true;
|
||||
try
|
||||
{
|
||||
var query = Context.Events.OrderBy(e => e.Name).Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
||||
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||
|
||||
var totalItems = await query.CountAsync();
|
||||
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync();
|
||||
var query = Context.Events
|
||||
.AsNoTracking()
|
||||
.OrderBy(e => e.Name).Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
||||
|
||||
var totalItems = await query.CountAsync(cancellationToken);
|
||||
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync(cancellationToken);
|
||||
|
||||
return new GridData<EventDefinition>
|
||||
{
|
||||
@@ -91,31 +108,82 @@
|
||||
Items = pagedData
|
||||
};
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
return new GridData<EventDefinition> { TotalItems = 0, Items = [] };
|
||||
}
|
||||
catch (JSDisconnectedException)
|
||||
{
|
||||
return new GridData<EventDefinition> { TotalItems = 0, Items = [] };
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isLoading = false;
|
||||
if (!_isDisposed)
|
||||
{
|
||||
_isLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteEventDefinition(EventDefinition evt)
|
||||
{
|
||||
//_isRowBlocked = true;
|
||||
if (_isDisposed) return;
|
||||
|
||||
var result = await DialogService
|
||||
.ShowMessageBox("Delete Event",
|
||||
(MarkupString)$"Are you sure want to delete <b>{evt.Name}</b>? This cannot be undone.",
|
||||
yesText:"Yes",
|
||||
noText:"Cancel");
|
||||
|
||||
if (result == true)
|
||||
try
|
||||
{
|
||||
Context.Events.Remove(evt!);
|
||||
await Context.SaveChangesAsync();
|
||||
Snackbar.Add($"Delete event: Delete of Event {evt.Name}", Severity.Info);
|
||||
}
|
||||
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||
|
||||
//_isRowBlocked = false;
|
||||
StateHasChanged();
|
||||
await _dataGrid.ReloadServerData();
|
||||
var result = await DialogService
|
||||
.ShowMessageBox("Delete Event",
|
||||
(MarkupString)$"Are you sure want to delete <b>{evt.Name}</b>? This cannot be undone.",
|
||||
yesText:"Yes",
|
||||
noText:"Cancel");
|
||||
|
||||
if (_isDisposed) return;
|
||||
|
||||
if (result == true)
|
||||
{
|
||||
Context.Events.Remove(evt!);
|
||||
await Context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Snackbar.Add($"Event {evt.Name} deleted", Severity.Info);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isDisposed)
|
||||
{
|
||||
StateHasChanged();
|
||||
await _dataGrid.ReloadServerData();
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Component was disposed, ignore
|
||||
}
|
||||
catch (JSDisconnectedException)
|
||||
{
|
||||
// JS connection lost, ignore
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Snackbar.Add($"Error deleting event: {ex.Message}", Severity.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
_isDisposed = true;
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_cancellationTokenSource = null;
|
||||
}
|
||||
await ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +178,7 @@
|
||||
_scheduledTeams = _scheduledTeams.Where(t => t != unassignedTeam);
|
||||
else
|
||||
{
|
||||
_scheduledTeams = _scheduledTeams.Concat(new[] { unassignedTeam });
|
||||
_scheduledTeams = _scheduledTeams.Concat([unassignedTeam]);
|
||||
}
|
||||
await SaveScheduledTeams();
|
||||
}
|
||||
@@ -216,6 +216,7 @@
|
||||
|
||||
_teams
|
||||
= await Context.Teams
|
||||
.AsNoTracking()
|
||||
.Include(e => e.Event)
|
||||
.Include(e => e.Students)
|
||||
.OrderBy(e => e.Event.Name)
|
||||
@@ -224,6 +225,7 @@
|
||||
|
||||
_students =
|
||||
await Context.Students
|
||||
.AsNoTracking()
|
||||
.Include(e => e.Teams)
|
||||
.ThenInclude(e => e.Captain)
|
||||
.Include(e => e.EventRankings)
|
||||
@@ -311,13 +313,13 @@
|
||||
|
||||
// Try recommendation strategies in priority order
|
||||
var scheduler = new UnassignedStudentScheduler(_teams, _solution.TimeSlots);
|
||||
var strategies = new[]
|
||||
{
|
||||
UnassignedScheduleStrategy[] strategies =
|
||||
[
|
||||
UnassignedScheduleStrategy.LevelOfEffort,
|
||||
UnassignedScheduleStrategy.BiggestGroup,
|
||||
UnassignedScheduleStrategy.AnyNotMeetingAlready,
|
||||
UnassignedScheduleStrategy.IndividualEvents
|
||||
};
|
||||
];
|
||||
|
||||
_possibleAdditions = strategies
|
||||
.Select(strategy => scheduler.ScheduleStrategy(strategy))
|
||||
|
||||
@@ -140,11 +140,13 @@ else
|
||||
.OrderBy(e => e.Event.Name)
|
||||
.ToArray();
|
||||
|
||||
var events = await Context.Events.ToArrayAsync();
|
||||
var events = await Context.Events
|
||||
.AsNoTracking()
|
||||
.ToArrayAsync();
|
||||
var remainingEvents =
|
||||
events
|
||||
.Where(e => _eventStudentRankings.All(est => est.Event.Id != e.Id))
|
||||
.Select(e => new EventStudentRankings { Event = e, StudentRanking = Array.Empty<Tuple<Student, int>>() })
|
||||
.Select(e => new EventStudentRankings { Event = e, StudentRanking = [] })
|
||||
.OrderBy(e => e.Event.Name)
|
||||
.ToArray();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
@page "/students"
|
||||
@attribute [Authorize]
|
||||
@implements IAsyncDisposable
|
||||
@using Microsoft.EntityFrameworkCore
|
||||
@using WebApp.Models
|
||||
@using WebApp.Components.Shared.Components
|
||||
@@ -68,18 +69,34 @@
|
||||
@code {
|
||||
MudDataGrid<Student> _dataGrid = null!;
|
||||
private bool _isLoading = true;
|
||||
private CancellationTokenSource? _cancellationTokenSource;
|
||||
private bool _isDisposed = false;
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
_cancellationTokenSource = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
private async Task<GridData<Student>> ServerReload(GridState<Student> state)
|
||||
{
|
||||
if (_isDisposed)
|
||||
{
|
||||
return new GridData<Student> { TotalItems = 0, Items = [] };
|
||||
}
|
||||
|
||||
_isLoading = true;
|
||||
try
|
||||
{
|
||||
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||
|
||||
var query =
|
||||
Context.Students.OrderBy(e => e.LastName)
|
||||
Context.Students
|
||||
.AsNoTracking()
|
||||
.OrderBy(e => e.LastName)
|
||||
.Where(state.FilterDefinitions).OrderBy(state.SortDefinitions);
|
||||
|
||||
var totalItems = await query.CountAsync();
|
||||
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync();
|
||||
var totalItems = await query.CountAsync(cancellationToken);
|
||||
var pagedData = await query.Skip(state.Page * state.PageSize).Take(state.PageSize).ToArrayAsync(cancellationToken);
|
||||
|
||||
return new GridData<Student>
|
||||
{
|
||||
@@ -87,31 +104,82 @@
|
||||
Items = pagedData
|
||||
};
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
return new GridData<Student> { TotalItems = 0, Items = [] };
|
||||
}
|
||||
catch (JSDisconnectedException)
|
||||
{
|
||||
return new GridData<Student> { TotalItems = 0, Items = [] };
|
||||
}
|
||||
finally
|
||||
{
|
||||
_isLoading = false;
|
||||
if (!_isDisposed)
|
||||
{
|
||||
_isLoading = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task DeleteStudent(Student student)
|
||||
{
|
||||
//_isRowBlocked = true;
|
||||
if (_isDisposed) return;
|
||||
|
||||
var result = await DialogService
|
||||
.ShowMessageBox("Delete student",
|
||||
(MarkupString)$"Are you sure want to delete <b>{student.Name}</b>? This cannot be undone.",
|
||||
yesText:"Yes",
|
||||
noText:"Cancel");
|
||||
|
||||
if (result == true)
|
||||
try
|
||||
{
|
||||
Context.Students.Remove(student!);
|
||||
await Context.SaveChangesAsync();
|
||||
Snackbar.Add($"Delete event: Delete of Student {student.Name}", Severity.Info);
|
||||
}
|
||||
var cancellationToken = _cancellationTokenSource?.Token ?? CancellationToken.None;
|
||||
|
||||
//_isRowBlocked = false;
|
||||
StateHasChanged();
|
||||
await _dataGrid.ReloadServerData();
|
||||
var result = await DialogService
|
||||
.ShowMessageBox("Delete student",
|
||||
(MarkupString)$"Are you sure want to delete <b>{student.Name}</b>? This cannot be undone.",
|
||||
yesText:"Yes",
|
||||
noText:"Cancel");
|
||||
|
||||
if (_isDisposed) return;
|
||||
|
||||
if (result == true)
|
||||
{
|
||||
Context.Students.Remove(student!);
|
||||
await Context.SaveChangesAsync(cancellationToken);
|
||||
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Snackbar.Add($"Student {student.Name} deleted", Severity.Info);
|
||||
}
|
||||
}
|
||||
|
||||
if (!_isDisposed)
|
||||
{
|
||||
StateHasChanged();
|
||||
await _dataGrid.ReloadServerData();
|
||||
}
|
||||
}
|
||||
catch (TaskCanceledException)
|
||||
{
|
||||
// Component was disposed, ignore
|
||||
}
|
||||
catch (JSDisconnectedException)
|
||||
{
|
||||
// JS connection lost, ignore
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
Snackbar.Add($"Error deleting student: {ex.Message}", Severity.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (!_isDisposed)
|
||||
{
|
||||
_isDisposed = true;
|
||||
_cancellationTokenSource?.Cancel();
|
||||
_cancellationTokenSource?.Dispose();
|
||||
_cancellationTokenSource = null;
|
||||
}
|
||||
await ValueTask.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,6 +174,7 @@
|
||||
{
|
||||
// Load all students with their teams
|
||||
var students = await Context.Students
|
||||
.AsNoTracking()
|
||||
.Include(s => s.Teams)
|
||||
.ThenInclude(t => t.Event)
|
||||
.Include(s => s.Teams)
|
||||
@@ -270,7 +271,7 @@
|
||||
Student = student,
|
||||
Events = student.Teams?.Where(t => t?.Event != null)
|
||||
.Select(t => t.Event)
|
||||
.ToList() ?? new List<EventDefinition>()
|
||||
.ToList() ?? []
|
||||
};
|
||||
|
||||
return ValidationService.ValidateStudentStatistics(stats, ValidationContext.StudentRegistration);
|
||||
|
||||
@@ -71,7 +71,9 @@
|
||||
.Include(e => e.Event)
|
||||
.Include(e => e.Students)
|
||||
.FirstOrDefaultAsync(m => m.Id == Id);
|
||||
_students = await Context.Students.ToListAsync();
|
||||
_students = await Context.Students
|
||||
.AsNoTracking()
|
||||
.ToListAsync();
|
||||
_selectedStudents = Team?.Students.ToList();
|
||||
|
||||
if (Team is null)
|
||||
|
||||
@@ -218,6 +218,7 @@ else
|
||||
{
|
||||
_teams
|
||||
= await Context.Teams
|
||||
.AsNoTracking()
|
||||
.Include(e => e.Event)
|
||||
.Include(e => e.Students)
|
||||
.OrderByEventFormatFirst()
|
||||
@@ -228,6 +229,7 @@ else
|
||||
_maxTeamSize = _teams.Max(t => t.Students.Count);
|
||||
_students =
|
||||
await Context.Students
|
||||
.AsNoTracking()
|
||||
.Include(e => e.Teams)
|
||||
.ThenInclude(e => e.Captain)
|
||||
.Include(e => e.EventRankings)
|
||||
|
||||
@@ -9,10 +9,12 @@ namespace WebApp;
|
||||
public sealed class LocalStorageService
|
||||
{
|
||||
private readonly IJSRuntime _jsRuntime;
|
||||
private readonly ILogger<LocalStorageService> _logger;
|
||||
|
||||
public LocalStorageService(IJSRuntime jsRuntime)
|
||||
public LocalStorageService(IJSRuntime jsRuntime, ILogger<LocalStorageService> logger)
|
||||
{
|
||||
_jsRuntime = jsRuntime;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -47,7 +49,7 @@ public sealed class LocalStorageService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to save boolean to localStorage [{key}]: {ex.Message}");
|
||||
_logger.LogWarning(ex, "Failed to save boolean to localStorage [{Key}]", key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +85,7 @@ public sealed class LocalStorageService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to save integer to localStorage [{key}]: {ex.Message}");
|
||||
_logger.LogWarning(ex, "Failed to save integer to localStorage [{Key}]", key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,14 +102,14 @@ public sealed class LocalStorageService
|
||||
if (!string.IsNullOrEmpty(json))
|
||||
{
|
||||
var array = JsonSerializer.Deserialize<int[]>(json);
|
||||
return array ?? Array.Empty<int>();
|
||||
return array ?? [];
|
||||
}
|
||||
return Array.Empty<int>();
|
||||
return [];
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to load integer array from localStorage [{key}]: {ex.Message}");
|
||||
return Array.Empty<int>();
|
||||
_logger.LogWarning(ex, "Failed to load integer array from localStorage [{Key}]", key);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +127,7 @@ public sealed class LocalStorageService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to save integer array to localStorage [{key}]: {ex.Message}");
|
||||
_logger.LogWarning(ex, "Failed to save integer array to localStorage [{Key}]", key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +143,7 @@ public sealed class LocalStorageService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to remove from localStorage [{key}]: {ex.Message}");
|
||||
_logger.LogWarning(ex, "Failed to remove from localStorage [{Key}]", key);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +158,7 @@ public sealed class LocalStorageService
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to clear localStorage: {ex.Message}");
|
||||
_logger.LogWarning(ex, "Failed to clear localStorage");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,15 +33,14 @@ namespace WebApp.Logging
|
||||
LogEventLevel.Information,
|
||||
null, // No exception at Info level
|
||||
messageTemplate,
|
||||
new[]
|
||||
{
|
||||
[
|
||||
new LogEventProperty("OriginalMessage",
|
||||
new ScalarValue(logEvent.MessageTemplate.Render(logEvent.Properties))),
|
||||
new LogEventProperty("SourceContext",
|
||||
logEvent.Properties.GetValueOrDefault("SourceContext") ?? new ScalarValue("Unknown")),
|
||||
new LogEventProperty("RequestPath",
|
||||
logEvent.Properties.GetValueOrDefault("RequestPath") ?? new ScalarValue("Unknown"))
|
||||
});
|
||||
]);
|
||||
|
||||
_wrappedSink.Emit(rewrittenEvent);
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ public class EventDefinitionService
|
||||
|
||||
// Get all existing careers from database (case-insensitive lookup)
|
||||
var existingCareers = await _context.Careers
|
||||
.AsNoTracking()
|
||||
.Where(c => !string.IsNullOrWhiteSpace(c.Name))
|
||||
.ToListAsync();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user