DATA-2: new schema entities + Minimal API endpoints + Scalar + DAL teardown
- Entities: Breeder->Contact, +Enclosure/ColorVariety/GerbilPhoto/HealthRecord/WeightRecord;
Gerbil expanded (single Genotype text col, Status/Gender enums-as-string, FK ids,
ImportSource/ExternalRef provenance); Litter Strength->TotalBorn +ExpectedGoHomeDate/Notes.
ColorVariety HasData seed = 18 from GEN-1 catalog. Gerbil<->Litter cycle handled
(SetNull/Restrict). Enums stored as strings.
- Minimal API (no controllers): Endpoints/*.cs MapGroup+TypedResults for gerbils, litters,
contacts, enclosures, color-varieties, health/weight-records, inbreeding (converted from
controller, same routes/shapes), photos (Oscar contract: GET array/POST multipart/DELETE,
url /photos/files/{fileName}). Gridify paged {items,totalCount,page,pageSize}, camelCase,
409 conflict-deletes, flat FK ids, litter parent-gender validation (400 {code,...}).
- Scalar replaces Swashbuckle (AddOpenApi/MapOpenApi + MapScalarApiReference at /scalar);
launchUrl swagger->scalar. GenericRepository/UnitOfWork/Converters deleted; DbContext direct.
- InbreedingService reads real FK props now; pure calculator + 8 tests untouched.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,28 +1,107 @@
|
||||
using GerbilManagerWebAPI.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
public class ApplicationContext : DbContext
|
||||
{
|
||||
public ApplicationContext(DbContextOptions options)
|
||||
: base(options)
|
||||
public ApplicationContext(DbContextOptions options) : base(options)
|
||||
{
|
||||
}
|
||||
|
||||
public DbSet<Gerbil> Gerbils => Set<Gerbil>();
|
||||
public DbSet<Litter> Litters => Set<Litter>();
|
||||
public DbSet<Contact> Contacts => Set<Contact>();
|
||||
public DbSet<Enclosure> Enclosures => Set<Enclosure>();
|
||||
public DbSet<ColorVariety> ColorVarieties => Set<ColorVariety>();
|
||||
public DbSet<GerbilPhoto> GerbilPhotos => Set<GerbilPhoto>();
|
||||
public DbSet<HealthRecord> HealthRecords => Set<HealthRecord>();
|
||||
public DbSet<WeightRecord> WeightRecords => Set<WeightRecord>();
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<Gerbil>().ToTable("Gerbils");
|
||||
modelBuilder.Entity<Litter>().ToTable("Litters");
|
||||
modelBuilder.Entity<Breeder>().ToTable("Breeders");
|
||||
modelBuilder.Entity<Gerbil>(e =>
|
||||
{
|
||||
// Enums persisted as their string names (readable, Gridify-friendly).
|
||||
e.Property(g => g.Gender).HasConversion<string>();
|
||||
e.Property(g => g.Status).HasConversion<string>();
|
||||
|
||||
modelBuilder.Entity<Gerbil>().HasOne(entity => entity.Litter);
|
||||
modelBuilder.Entity<Litter>().HasOne(entity => entity.Father);
|
||||
modelBuilder.Entity<Litter>().HasOne(entity => entity.Mother);
|
||||
e.HasOne(g => g.Litter).WithMany()
|
||||
.HasForeignKey(g => g.LitterId).OnDelete(DeleteBehavior.SetNull);
|
||||
e.HasOne(g => g.OriginContact).WithMany()
|
||||
.HasForeignKey(g => g.OriginContactId).OnDelete(DeleteBehavior.Restrict);
|
||||
e.HasOne(g => g.ReceiverContact).WithMany()
|
||||
.HasForeignKey(g => g.ReceiverContactId).OnDelete(DeleteBehavior.Restrict);
|
||||
e.HasOne(g => g.Enclosure).WithMany(en => en.Gerbils)
|
||||
.HasForeignKey(g => g.EnclosureId).OnDelete(DeleteBehavior.SetNull);
|
||||
e.HasOne(g => g.ColorVariety).WithMany()
|
||||
.HasForeignKey(g => g.ColorVarietyId).OnDelete(DeleteBehavior.SetNull);
|
||||
});
|
||||
|
||||
modelBuilder
|
||||
.Entity<Gerbil>()
|
||||
.Property(d => d.Gender)
|
||||
.HasConversion(new EnumToStringConverter<Gender>());
|
||||
modelBuilder.Entity<Litter>(e =>
|
||||
{
|
||||
e.HasOne(l => l.Father).WithMany()
|
||||
.HasForeignKey(l => l.FatherId).OnDelete(DeleteBehavior.Restrict);
|
||||
e.HasOne(l => l.Mother).WithMany()
|
||||
.HasForeignKey(l => l.MotherId).OnDelete(DeleteBehavior.Restrict);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<HealthRecord>(e =>
|
||||
{
|
||||
e.Property(h => h.Type).HasConversion<string>();
|
||||
e.HasOne<Gerbil>().WithMany()
|
||||
.HasForeignKey(h => h.GerbilId).OnDelete(DeleteBehavior.Cascade);
|
||||
});
|
||||
|
||||
modelBuilder.Entity<WeightRecord>(e =>
|
||||
e.HasOne<Gerbil>().WithMany()
|
||||
.HasForeignKey(w => w.GerbilId).OnDelete(DeleteBehavior.Cascade));
|
||||
|
||||
modelBuilder.Entity<GerbilPhoto>(e =>
|
||||
e.HasOne<Gerbil>().WithMany()
|
||||
.HasForeignKey(p => p.GerbilId).OnDelete(DeleteBehavior.Cascade));
|
||||
|
||||
SeedColorVarieties(modelBuilder);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Seed the 18 base varieties from the GEN-1 catalog (gerbil-manager-web/src/genetics/catalog.ts).
|
||||
/// Source of truth for names; the baseportal 78-variety extension lands in GEN-2 (re-seed later).
|
||||
/// </summary>
|
||||
private static void SeedColorVarieties(ModelBuilder modelBuilder)
|
||||
{
|
||||
(string Name, string Genotype)[] catalog =
|
||||
{
|
||||
("Pink Eyed White (PEW)", "AA chch DD EE GG pp spsp rere"),
|
||||
("Hermelin", "aa chch DD EE GG PP spsp rere"),
|
||||
("Himalaya", "AA chch DD EE GG PP spsp rere"),
|
||||
("Zobel", "aa cchmcchm DD EE gg PP spsp rere"),
|
||||
("Schwarzschimmel", "AA CC DD efef GG PP spsp rere"),
|
||||
("Rotaugenschimmel", "AA CC DD efef GG pp spsp rere"),
|
||||
("Agouti", "AA CC DD EE GG PP spsp rere"),
|
||||
("Schwarz", "aa CC DD EE GG PP spsp rere"),
|
||||
("Silberagouti", "AA CC DD EE gg PP spsp rere"),
|
||||
("Anthrazit", "aa CC DD EE gg PP spsp rere"),
|
||||
("Algierfuchs", "AA CC DD ee GG PP spsp rere"),
|
||||
("Blau", "aa CC dd EE GG PP spsp rere"),
|
||||
("Gold", "AA CC DD EE GG pp spsp rere"),
|
||||
("Platin", "aa CC DD EE GG pp spsp rere"),
|
||||
("Goldfuchs", "AA CC DD ee GG pp spsp rere"),
|
||||
("Rotfuchs", "aa CC DD ee GG pp spsp rere"),
|
||||
("dd Gold", "AA CC dd EE GG pp spsp rere"),
|
||||
("dd Platin", "aa CC dd EE GG pp spsp rere"),
|
||||
};
|
||||
|
||||
var rows = new ColorVariety[catalog.Length];
|
||||
for (int i = 0; i < catalog.Length; i++)
|
||||
{
|
||||
rows[i] = new ColorVariety
|
||||
{
|
||||
// Stable, deterministic GUIDs so the HasData seed is migration-stable.
|
||||
Id = new Guid($"00000000-0000-0000-0000-{(i + 1):D12}"),
|
||||
Name = catalog[i].Name,
|
||||
CanonicalGenotype = catalog[i].Genotype,
|
||||
SortOrder = i,
|
||||
};
|
||||
}
|
||||
modelBuilder.Entity<ColorVariety>().HasData(rows);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user