Remove Team.Number

Add Team.Identifier
This commit is contained in:
2025-10-03 12:47:05 -04:00
parent 05e5e69d0b
commit 6407dfca71
15 changed files with 338 additions and 43 deletions
+1 -1
View File
@@ -132,7 +132,7 @@ namespace Core.Calculation
where students.Any()
select new Team
{
TeamId = _events[e].Name,
Identifier = _events[e].Name,
Event = _events[e],
Students = students.ToList()
};
@@ -67,7 +67,7 @@ public class UnassignedStudentScheduler
private IEnumerable<Team> GetAvailableTeams_BiggestGroup(
IEnumerable<Team> scheduledTeams, IEnumerable<Student> assignedStudents) =>
_teams
.Where(t => scheduledTeams.All(st => st.TeamId != t.TeamId))
.Where(t => scheduledTeams.All(st => st.Identifier != t.Identifier))
.Select(t => t.CloneWithOmittedStudents(assignedStudents))
.Where(t => t.Students.Count > 1) //|| t.Event.EventFormat is EventFormat.Individual
//.OrderBy(t => scheduledTeams.Count(st => st.Name == t.Name))
@@ -78,7 +78,7 @@ public class UnassignedStudentScheduler
private IEnumerable<Team> GetAvailableTeams_Individual(
IEnumerable<Team> scheduledTeams, IEnumerable<Student> assignedStudents) =>
_teams
.Where(t => scheduledTeams.All(st => st.TeamId != t.TeamId))
.Where(t => scheduledTeams.All(st => st.Identifier != t.Identifier))
.Where(t => t.Event.EventFormat == EventFormat.Individual || t.Students.Count == 1)
.Select(t => t.CloneWithOmittedStudents(assignedStudents))
.Where(t => t.Students.Count > 0);
@@ -87,7 +87,7 @@ public class UnassignedStudentScheduler
private IEnumerable<Team> GetAvailableTeams_AnyNotMeetingAlready(
IEnumerable<Team> scheduledTeams, IEnumerable<Student> assignedStudents) =>
_teams
.Where(t => scheduledTeams.All(st => st.TeamId != t.TeamId))
.Where(t => scheduledTeams.All(st => st.Identifier != t.Identifier))
.Select(t => t.CloneWithOmittedStudents(assignedStudents))
.Where(t => t.Students.Count > 0);
@@ -102,7 +102,7 @@ public class UnassignedStudentScheduler
private IEnumerable<Team> GetAvailableTeams_LevelOfEffort(
IEnumerable<Team> scheduledTeams, IEnumerable<Student> assignedStudents) =>
_teams
.Where(t => scheduledTeams.All(st => st.TeamId != t.TeamId))
.Where(t => scheduledTeams.All(st => st.Identifier != t.Identifier))
.Select(t => t.CloneWithOmittedStudents(assignedStudents))
.Where(t => t.Students.Count > 1) //|| t.Event.EventFormat is EventFormat.Individual
//.OrderBy(t => scheduledTeams.Count(st => st.Name == t.Name))
@@ -114,7 +114,7 @@ public class UnassignedStudentScheduler
// sort by how many teammembers are already in that timeslot, descending
foreach (var timeslot in _timeSlots.OrderBy(ts => ts.SelectMany(t => t.Students).Count(team.Students.Contains)))
{
if (timeslot.Any(t => t.TeamId == team.TeamId))
if (timeslot.Any(t => t.Identifier == team.Identifier))
continue;
timeslot.Add(team);
break;
+1 -1
View File
@@ -8,6 +8,6 @@ public class PartialTeam : Team
{
var remainingStudents = Students.Where(s => !studentsToOmit.Contains(s)).ToList();
var omittedStudents = OmittedStudents.Union(Students.Where(studentsToOmit.Contains)).Distinct().ToList();
return new PartialTeam{TeamId = TeamId, Event = Event, Students = remainingStudents, OmittedStudents = omittedStudents };
return new PartialTeam{Identifier = Identifier, Event = Event, Students = remainingStudents, OmittedStudents = omittedStudents };
}
}
+8 -14
View File
@@ -4,22 +4,16 @@ namespace Core.Entities;
public class Team
{
public int Id { get; set; }
[Display(Name = "Team Number")]
public int? Number { get; set; }
public EventDefinition Event
{
get;
set;
}
public EventDefinition Event { get; set; }
public List<Student> Students { get; set; } = [];
public Student? Captain { get; set; }
[Display(Name = "Team Id")]
public string? TeamId { get; set; }
[Display(Name = "Team Identifier")]
[StringLength(32)]
public string? Identifier { get; set; }
// public Tuple<DateTime,DateTime?>? RegionalTimeSlotObj
@@ -54,10 +48,10 @@ public class Team
var studentsToOmitList = studentsToOmit.ToList();
var omittedStudents = Students.Where(studentsToOmitList.Contains).ToList();
if (!omittedStudents.Any())
return new Team{Captain = Captain, Event = Event, Students = Students.ToList(), TeamId = TeamId, Number = Number};
return new Team{Captain = Captain, Event = Event, Students = Students.ToList(), Identifier = Identifier};
var remainingStudents = Students.Where(s => !studentsToOmitList.Contains(s)).ToList();
return new PartialTeam { Number = Number, Event = Event, Students = remainingStudents, OmittedStudents = omittedStudents};
return new PartialTeam { Event = Event, Students = remainingStudents, OmittedStudents = omittedStudents};
}
public Team Clone() => CloneWithOmittedStudents([]);
@@ -65,6 +59,6 @@ public class Team
public override string ToString()
{
return $"{Event.Name} {(Number != null ? $"(#{Number})" : "")}";
return $"{Event.Name} {(Identifier != null ? $"({Identifier})" : "")}";
}
}
+3 -3
View File
@@ -39,7 +39,7 @@ namespace Core.Parsers
foreach (var team in _teams)
{
csv.WriteField(team.TeamId);
csv.WriteField(team.Identifier);
csv.WriteField(team.Event.Name);
foreach (var teamStudent in team.Students)
{
@@ -146,14 +146,14 @@ namespace Core.Parsers
{
if (@event.EventFormat is EventFormat.Team)
{
teams.Add(new Team { Event = @event, Students = teamStudents, Captain = captain, TeamId = teamNumber});
teams.Add(new Team { Event = @event, Students = teamStudents, Captain = captain, Identifier = teamNumber});
}
else if (@event.EventFormat is EventFormat.Individual)
{
foreach (var student in teamStudents)
{
teams.Add(new Team{Event = @event,
Students = [student], Captain = student, TeamId = teamNumber});
Students = [student], Captain = student, Identifier = teamNumber});
}
}
}
-2
View File
@@ -74,8 +74,6 @@ namespace Data
builder.HasOne(e => e.Captain);
builder.Property(e => e.Number).IsRequired(false);
//builder.i
}
}
public class StudentEventRankingConfiguration : IEntityTypeConfiguration<StudentEventRanking>
+255
View File
@@ -0,0 +1,255 @@
// <auto-generated />
using Data;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace Data.Migrations
{
[DbContext(typeof(AppDbContext))]
[Migration("20251003164320_TeamIdentifier")]
partial class TeamIdentifier
{
/// <inheritdoc />
protected override void BuildTargetModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "9.0.8");
modelBuilder.Entity("Core.Entities.EventDefinition", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("ChapterEligibilityCountRegionals")
.HasColumnType("INTEGER");
b.Property<int>("ChapterEligibilityCountState")
.HasColumnType("INTEGER");
b.Property<string>("Description")
.HasMaxLength(1024)
.HasColumnType("TEXT");
b.Property<string>("Documentation")
.HasMaxLength(64)
.HasColumnType("TEXT");
b.Property<string>("Eligibility")
.IsRequired()
.HasMaxLength(256)
.HasColumnType("TEXT");
b.Property<int>("EventFormat")
.HasColumnType("INTEGER");
b.Property<int?>("LevelOfEffort")
.HasColumnType("INTEGER");
b.Property<int>("MaxTeamSize")
.HasColumnType("INTEGER");
b.Property<int>("MinTeamSize")
.HasColumnType("INTEGER");
b.Property<string>("Name")
.IsRequired()
.HasMaxLength(128)
.HasColumnType("TEXT");
b.Property<string>("Notes")
.HasMaxLength(1024)
.HasColumnType("TEXT");
b.Property<bool>("OnSiteActivity")
.HasColumnType("INTEGER");
b.Property<bool>("Presubmission")
.HasColumnType("INTEGER");
b.Property<string>("SemifinalistActivity")
.HasMaxLength(100)
.HasColumnType("TEXT");
b.Property<string>("ShortName")
.IsRequired()
.HasMaxLength(40)
.HasColumnType("TEXT");
b.Property<string>("Theme")
.HasMaxLength(4096)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("Name");
b.ToTable("Events");
});
modelBuilder.Entity("Core.Entities.Student", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<string>("Email")
.HasColumnType("TEXT");
b.Property<string>("FirstName")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<int>("Grade")
.HasColumnType("INTEGER");
b.Property<string>("LastName")
.IsRequired()
.HasMaxLength(50)
.HasColumnType("TEXT");
b.Property<string>("NationalId")
.HasColumnType("TEXT");
b.Property<int?>("OfficerRole")
.HasColumnType("INTEGER");
b.Property<string>("PhoneNumber")
.HasColumnType("TEXT");
b.Property<string>("RegionalId")
.HasColumnType("TEXT");
b.Property<string>("StateId")
.HasColumnType("TEXT");
b.Property<int>("TsaYear")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("Students");
});
modelBuilder.Entity("Core.Entities.StudentEventRanking", b =>
{
b.Property<int>("EventDefinitionId")
.HasColumnType("INTEGER");
b.Property<int>("StudentId")
.HasColumnType("INTEGER");
b.Property<int>("Rank")
.HasColumnType("INTEGER");
b.HasKey("EventDefinitionId", "StudentId");
b.HasIndex("StudentId");
b.ToTable("StudentEventRanking");
});
modelBuilder.Entity("Core.Entities.Team", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int?>("CaptainId")
.HasColumnType("INTEGER");
b.Property<int>("EventId")
.HasColumnType("INTEGER");
b.Property<string>("Identifier")
.HasMaxLength(32)
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("CaptainId");
b.HasIndex("EventId");
b.ToTable("Teams");
});
modelBuilder.Entity("StudentTeam", b =>
{
b.Property<int>("StudentsId")
.HasColumnType("INTEGER");
b.Property<int>("TeamsId")
.HasColumnType("INTEGER");
b.HasKey("StudentsId", "TeamsId");
b.HasIndex("TeamsId");
b.ToTable("StudentTeam");
});
modelBuilder.Entity("Core.Entities.StudentEventRanking", b =>
{
b.HasOne("Core.Entities.EventDefinition", "EventDefinition")
.WithMany()
.HasForeignKey("EventDefinitionId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Core.Entities.Student", "Student")
.WithMany("EventRankings")
.HasForeignKey("StudentId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("EventDefinition");
b.Navigation("Student");
});
modelBuilder.Entity("Core.Entities.Team", b =>
{
b.HasOne("Core.Entities.Student", "Captain")
.WithMany()
.HasForeignKey("CaptainId");
b.HasOne("Core.Entities.EventDefinition", "Event")
.WithMany()
.HasForeignKey("EventId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Captain");
b.Navigation("Event");
});
modelBuilder.Entity("StudentTeam", b =>
{
b.HasOne("Core.Entities.Student", null)
.WithMany()
.HasForeignKey("StudentsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("Core.Entities.Team", null)
.WithMany()
.HasForeignKey("TeamsId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("Core.Entities.Student", b =>
{
b.Navigation("EventRankings");
});
#pragma warning restore 612, 618
}
}
}
@@ -0,0 +1,53 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Data.Migrations
{
/// <inheritdoc />
public partial class TeamIdentifier : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "Identifier",
table: "Teams",
type: "TEXT",
maxLength: 32,
nullable: true);
migrationBuilder.Sql("UPDATE Teams SET Identifier = Number");
migrationBuilder.DropColumn(
name: "Number",
table: "Teams");
migrationBuilder.DropColumn(
name: "TeamId",
table: "Teams");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "Identifier",
table: "Teams");
migrationBuilder.AddColumn<int>(
name: "Number",
table: "Teams",
type: "INTEGER",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "TeamId",
table: "Teams",
type: "TEXT",
nullable: true);
}
}
}
+2 -4
View File
@@ -163,10 +163,8 @@ namespace Data.Migrations
b.Property<int>("EventId")
.HasColumnType("INTEGER");
b.Property<int?>("Number")
.HasColumnType("INTEGER");
b.Property<string>("TeamId")
b.Property<string>("Identifier")
.HasMaxLength(32)
.HasColumnType("TEXT");
b.HasKey("Id");
@@ -236,7 +236,7 @@
.Include(e => e.Event)
.Include(e => e.Students)
.OrderBy(e => e.Event.Name)
.ThenBy(e => e.Number)
.ThenBy(e => e.Identifier)
.ToArrayAsync();
_students =
@@ -21,7 +21,7 @@
<MudSelectItem T="EventDefinition" Value="@(evt)"></MudSelectItem>
}
</MudSelect>
<MudTextField T="int?" Label="Number" @bind-Value="Team.Number" For="@(() => Team.Number)"></MudTextField>
<MudTextField T="string?" Label="Number" @bind-Value="Team.Identifier" For="@(() => Team.Identifier)"></MudTextField>
</MudPaper>
</MudItem>
@@ -46,7 +46,7 @@
private async Task AddTeam()
{
Team.TeamId = Team.Event.Name;
Team.Identifier = Team.Event.Name;
Context.Teams.Add(Team);
await Context.SaveChangesAsync();
+4 -7
View File
@@ -6,7 +6,7 @@
<PageTitle>Edit Team - TSA Chapter Organizer</PageTitle>
<MudText Typo="Typo.h3">Edit</MudText>
<MudText Typo="Typo.h4">Team@(Team == null ? "" : $" ({Team.Event.Name} #{Team.Number})")</MudText>
<MudText Typo="Typo.h4">Team @(Team.ToString())</MudText>
@if (Team is null)
{
@@ -32,8 +32,8 @@ else
}
</MudSelect>
<MudTextField T="Student" Label="Captain" @bind-Value="Team.Captain" For="@(() => Team.Captain)" Required="false" Clearable="true"></MudTextField>
<MudNumericField T="int?" Label="Number" @bind-Value="Team.Number" For="@(() => Team.Number)" Required="false" Clearable="true"></MudNumericField>
<MudTextField T="string?" Label="TeamId" @bind-Value="Team.TeamId" For="@(() => Team.TeamId)" Required="false" Clearable="true"></MudTextField>
<MudNumericField T="string?" Label="Number" @bind-Value="Team.Identifier" For="@(() => Team.Identifier)" Required="false" Clearable="true"></MudNumericField>
<MudTextField T="string?" Label="Identifier" @bind-Value="Team.Identifier" For="@(() => Team.Identifier)" Required="false" Clearable="true"></MudTextField>
</MudPaper>
</MudItem>
</MudGrid>
@@ -73,10 +73,7 @@ else
{
case EventFormat.Individual when Team.Students.Count == 1:
Team.Captain ??= Team.Students[0];
Team.TeamId ??= Team.Captain.FirstName;
break;
case EventFormat.Team when Team.Number != null && Team.TeamId == null:
Team.TeamId = Team.Number.ToString();
Team.Identifier ??= Team.Captain.FirstName;
break;
}
}
@@ -107,7 +107,7 @@ else
.Include(e => e.Event)
.Include(e => e.Students)
.OrderBy(e => e.Event.Name)
.ThenBy(e => e.Number)
.ThenBy(e => e.Identifier)
.ToArrayAsync();
_maxTeamSize = _teams.Max(t => t.Students.Count);
@@ -88,7 +88,7 @@
.Include(e => e.Students)
.ThenInclude(e => e.EventRankings)
.OrderBy(e => e.Event.Name)
.ThenBy(e => e.Number)
.ThenBy(e => e.Identifier)
.Where(state.FilterDefinitions)
.OrderBy(state.SortDefinitions);
@@ -213,7 +213,7 @@ else
.Include(e => e.Event)
.Include(e => e.Students)
.OrderBy(e => e.Event.Name)
.ThenBy(e => e.Number)
.ThenBy(e => e.Identifier)
.ToArrayAsync();
_maxTeamSize = _teams.Max(t => t.Students.Count);