Add Related Careers functionality to EventDefinition entity and update related components

Introduced a many-to-many relationship between EventDefinition and Career entities, allowing for the association of multiple careers with an event. Updated the AppDbContext to include a DbSet for Careers and modified the EventDefinitionConfiguration to handle the new relationship. Enhanced the Create, Edit, and Details components to support input and display of related careers, including normalization and processing logic for career names. Updated the database schema to reflect these changes.
This commit is contained in:
2025-12-28 15:22:03 -05:00
parent 8967d0f8a4
commit 06b2db0b4c
12 changed files with 788 additions and 18 deletions
+19
View File
@@ -0,0 +1,19 @@
using System.ComponentModel.DataAnnotations;
namespace Core.Entities;
public class Career
{
public int Id { get; set; }
[Required]
[StringLength(200, MinimumLength = 1)]
[Display(Name = "Career Name")]
public string Name { get; set; } = null!;
public override string ToString()
{
return Name;
}
}
+5
View File
@@ -79,6 +79,11 @@ public class EventDefinition
public string? Description { get; set; }
public int? LevelOfEffort { get; set; }
public ICollection<Career> RelatedCareers { get; set; } = new List<Career>();
[System.ComponentModel.DataAnnotations.Schema.NotMapped]
public string? RelatedCareersText { get; set; }
public override string ToString()
{
return Name;
+57
View File
@@ -0,0 +1,57 @@
using System.Text.RegularExpressions;
namespace Core.Utility;
public static class CareerNormalizer
{
/// <summary>
/// Normalizes career names from multiline text input.
/// Strips bullet points, trims whitespace, and returns distinct normalized names.
/// </summary>
/// <param name="input">Multiline text input containing career names</param>
/// <returns>Collection of normalized career names (trimmed, with bullets removed)</returns>
public static IEnumerable<string> NormalizeCareerNames(string? input)
{
if (string.IsNullOrWhiteSpace(input))
{
return Enumerable.Empty<string>();
}
return input
.Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)
.Select(line => NormalizeSingleCareerName(line))
.Where(name => !string.IsNullOrWhiteSpace(name))
.Distinct(StringComparer.OrdinalIgnoreCase)
.ToList();
}
/// <summary>
/// Normalizes a single career name by stripping bullet points and trimming whitespace.
/// </summary>
/// <param name="careerName">The career name to normalize</param>
/// <returns>Normalized career name</returns>
private static string NormalizeSingleCareerName(string careerName)
{
if (string.IsNullOrWhiteSpace(careerName))
{
return string.Empty;
}
// Remove common bullet point characters (•, -, *, etc.) and trim
var normalized = Regex.Replace(careerName.Trim(), @"^[\u2022\u2023\u25E6\u2043\u2219\-\*\•]\s*", string.Empty, RegexOptions.Compiled);
return normalized.Trim();
}
/// <summary>
/// Finds or creates a career name for case-insensitive duplicate detection.
/// Returns the normalized (lowercase) version for comparison.
/// </summary>
/// <param name="careerName">The career name to normalize for comparison</param>
/// <returns>Lowercase normalized name for duplicate detection</returns>
public static string GetNormalizedKey(string careerName)
{
return NormalizeSingleCareerName(careerName).ToLowerInvariant();
}
}