using GerbilManagerWebAPI.Models; using Microsoft.EntityFrameworkCore; namespace GerbilManagerWebAPI.Genetics { /// /// Loads the pedigree out of the database into in-memory lookups (the home dataset /// is small) and delegates the actual maths to . /// /// Parent links live in EF shadow foreign keys: a gerbil's birth litter is /// Gerbils.LitterId; that litter's parents are Litters.FatherId and /// Litters.MotherId. /// public sealed class InbreedingService { private readonly ApplicationContext _db; public InbreedingService(ApplicationContext db) => _db = db; /// F for an existing gerbil, or null if no such gerbil exists. public InbreedingResult? ForGerbil(Guid id) { var calculator = BuildCalculator(); return calculator.Contains(id) ? calculator.ForIndividual(id) : null; } /// F for the hypothetical offspring of the given sire and dam. public InbreedingResult ForPairing(Guid? fatherId, Guid? motherId) { return BuildCalculator().ForOffspringOf(fatherId, motherId); } private PedigreeCalculator BuildCalculator() { var litters = _db.Litters .Select(l => new { l.Id, l.FatherId, l.MotherId }) .ToDictionary(l => l.Id, l => (l.FatherId, l.MotherId)); var gerbils = _db.Gerbils .Select(g => new { g.Id, g.Name, g.LitterId }) .ToList(); var parents = new Dictionary(gerbils.Count); var names = new Dictionary(gerbils.Count); foreach (var g in gerbils) { names[g.Id] = g.Name; Guid? father = null; Guid? mother = null; if (g.LitterId is Guid litterId && litters.TryGetValue(litterId, out var litterParents)) { father = litterParents.FatherId; mother = litterParents.MotherId; } parents[g.Id] = (father, mother); } return new PedigreeCalculator(parents, names); } } }