262 lines
11 KiB
C#
262 lines
11 KiB
C#
using MealPlan.Api.Models;
|
|
using Microsoft.EntityFrameworkCore;
|
|
|
|
namespace MealPlan.Api.Data;
|
|
|
|
/// <summary>
|
|
/// Database-first context for the existing PostgreSQL database.
|
|
/// Tables are mapped explicitly; this context never creates or alters schema.
|
|
/// </summary>
|
|
public class AppDbContext : DbContext
|
|
{
|
|
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
|
|
{
|
|
}
|
|
|
|
public DbSet<Recipe> Recipes => Set<Recipe>();
|
|
public DbSet<Ingredient> Ingredients => Set<Ingredient>();
|
|
public DbSet<RecipeStep> RecipeSteps => Set<RecipeStep>();
|
|
public DbSet<ApplicationUser> Users => Set<ApplicationUser>();
|
|
public DbSet<UserDailyGoal> UserDailyGoals => Set<UserDailyGoal>();
|
|
public DbSet<DrinkCatalogItem> DrinkCatalog => Set<DrinkCatalogItem>();
|
|
public DbSet<MealConsumption> MealConsumptions => Set<MealConsumption>();
|
|
public DbSet<DrinkConsumption> DrinkConsumptions => Set<DrinkConsumption>();
|
|
public DbSet<DietReminder> DietReminders => Set<DietReminder>();
|
|
public DbSet<IngredientCategory> IngredientCategories => Set<IngredientCategory>();
|
|
public DbSet<IngredientNutritionCatalogItem> IngredientNutritionCatalog => Set<IngredientNutritionCatalogItem>();
|
|
public DbSet<RefreshTokenEntity> RefreshTokens => Set<RefreshTokenEntity>();
|
|
public DbSet<MealPlanEntry> MealPlanEntries => Set<MealPlanEntry>();
|
|
public DbSet<UserFavoriteRecipe> UserFavoriteRecipes => Set<UserFavoriteRecipe>();
|
|
public DbSet<UserFavoriteCatalogItem> UserFavoriteCatalogItems => Set<UserFavoriteCatalogItem>();
|
|
public DbSet<DietUserProfile> DietUserProfiles => Set<DietUserProfile>();
|
|
public DbSet<DietGeneratorSession> DietGeneratorSessions => Set<DietGeneratorSession>();
|
|
public DbSet<DietGeneratorDraftMeal> DietGeneratorDraftMeals => Set<DietGeneratorDraftMeal>();
|
|
public DbSet<DietGeneratorDraftMealIngredient> DietGeneratorDraftMealIngredients =>
|
|
Set<DietGeneratorDraftMealIngredient>();
|
|
public DbSet<RecipeGeneratorSession> RecipeGeneratorSessions => Set<RecipeGeneratorSession>();
|
|
|
|
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
{
|
|
base.OnModelCreating(modelBuilder);
|
|
|
|
modelBuilder.HasDefaultSchema("diet");
|
|
|
|
modelBuilder.Entity<Recipe>(e =>
|
|
{
|
|
e.HasKey(r => r.Id);
|
|
e.Property(r => r.Id).UseIdentityByDefaultColumn();
|
|
e.Property(r => r.Protein).HasColumnType("numeric(6,2)");
|
|
e.Property(r => r.Fat).HasColumnType("numeric(6,2)");
|
|
e.Property(r => r.Carbs).HasColumnType("numeric(6,2)");
|
|
|
|
e.HasMany(r => r.Ingredients)
|
|
.WithOne(i => i.Recipe!)
|
|
.HasForeignKey(i => i.RecipeId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
|
|
e.HasMany(r => r.Steps)
|
|
.WithOne(s => s.Recipe!)
|
|
.HasForeignKey(s => s.RecipeId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<Ingredient>(e =>
|
|
{
|
|
e.HasKey(i => i.Id);
|
|
e.Property(i => i.Id).UseIdentityByDefaultColumn();
|
|
e.Property(i => i.AmountGrams).HasColumnType("numeric(8,2)");
|
|
e.HasOne(i => i.CatalogItem)
|
|
.WithMany()
|
|
.HasForeignKey(i => i.CatalogItemId)
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
});
|
|
|
|
modelBuilder.Entity<RecipeStep>(e =>
|
|
{
|
|
e.HasKey(s => s.Id);
|
|
e.Property(s => s.Id).UseIdentityByDefaultColumn();
|
|
});
|
|
|
|
modelBuilder.Entity<ApplicationUser>(e =>
|
|
{
|
|
e.HasKey(u => u.Id);
|
|
e.Property(u => u.Id).HasColumnType("uuid");
|
|
});
|
|
|
|
modelBuilder.Entity<UserDailyGoal>(e =>
|
|
{
|
|
e.HasKey(g => g.UserId);
|
|
e.Property(g => g.UserId).HasColumnType("uuid");
|
|
e.Property(g => g.ProteinGoalG).HasColumnType("numeric(6,2)");
|
|
e.Property(g => g.FatGoalG).HasColumnType("numeric(6,2)");
|
|
e.Property(g => g.CarbsGoalG).HasColumnType("numeric(6,2)");
|
|
e.HasOne(g => g.User)
|
|
.WithMany()
|
|
.HasForeignKey(g => g.UserId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<DrinkCatalogItem>(e =>
|
|
{
|
|
e.HasKey(d => d.Id);
|
|
e.Property(d => d.Id).UseIdentityByDefaultColumn();
|
|
e.Property(d => d.CaloriesPer100Ml).HasColumnType("numeric(6,2)");
|
|
});
|
|
|
|
modelBuilder.Entity<MealConsumption>(e =>
|
|
{
|
|
e.HasKey(m => m.Id);
|
|
e.Property(m => m.Id).UseIdentityByDefaultColumn();
|
|
e.Property(m => m.UserId).HasColumnType("uuid");
|
|
e.Property(m => m.Portions).HasColumnType("numeric(4,2)");
|
|
e.Property(m => m.ProteinG).HasColumnType("numeric(6,2)");
|
|
e.Property(m => m.FatG).HasColumnType("numeric(6,2)");
|
|
e.Property(m => m.CarbsG).HasColumnType("numeric(6,2)");
|
|
e.HasOne(m => m.User)
|
|
.WithMany()
|
|
.HasForeignKey(m => m.UserId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
e.HasOne(m => m.Recipe)
|
|
.WithMany()
|
|
.HasForeignKey(m => m.RecipeId)
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
});
|
|
|
|
modelBuilder.Entity<DrinkConsumption>(e =>
|
|
{
|
|
e.HasKey(d => d.Id);
|
|
e.Property(d => d.Id).UseIdentityByDefaultColumn();
|
|
e.Property(d => d.UserId).HasColumnType("uuid");
|
|
e.HasOne(d => d.User)
|
|
.WithMany()
|
|
.HasForeignKey(d => d.UserId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
e.HasOne(d => d.DrinkCatalog)
|
|
.WithMany()
|
|
.HasForeignKey(d => d.DrinkCatalogId)
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
});
|
|
|
|
modelBuilder.Entity<DietReminder>(e =>
|
|
{
|
|
e.HasKey(r => r.Id);
|
|
e.Property(r => r.Id).UseIdentityByDefaultColumn();
|
|
e.Property(r => r.UserId).HasColumnType("uuid");
|
|
e.HasOne(r => r.User)
|
|
.WithMany()
|
|
.HasForeignKey(r => r.UserId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<IngredientCategory>(e =>
|
|
{
|
|
e.HasKey(c => c.Id);
|
|
e.Property(c => c.Id).UseIdentityByDefaultColumn();
|
|
});
|
|
|
|
modelBuilder.Entity<IngredientNutritionCatalogItem>(e =>
|
|
{
|
|
e.HasKey(i => i.Id);
|
|
e.Property(i => i.Id).UseIdentityByDefaultColumn();
|
|
e.Property(i => i.ProteinGPer100G).HasColumnType("numeric(6,2)");
|
|
e.Property(i => i.FatGPer100G).HasColumnType("numeric(6,2)");
|
|
e.Property(i => i.CarbsGPer100G).HasColumnType("numeric(6,2)");
|
|
e.Property(i => i.FiberGPer100G).HasColumnType("numeric(6,2)");
|
|
e.HasOne(i => i.Category)
|
|
.WithMany(c => c.Items)
|
|
.HasForeignKey(i => i.CategoryId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
});
|
|
|
|
modelBuilder.Entity<RefreshTokenEntity>(e =>
|
|
{
|
|
e.HasKey(t => t.Token);
|
|
e.Property(t => t.UserId).HasColumnType("uuid");
|
|
e.HasOne(t => t.User)
|
|
.WithMany()
|
|
.HasForeignKey(t => t.UserId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<MealPlanEntry>(e =>
|
|
{
|
|
e.HasKey(m => m.Id);
|
|
e.Property(m => m.Id).UseIdentityByDefaultColumn();
|
|
e.Property(m => m.UserId).HasColumnType("uuid");
|
|
e.Property(m => m.Portions).HasColumnType("numeric(4,2)");
|
|
e.HasOne(m => m.User).WithMany().HasForeignKey(m => m.UserId).OnDelete(DeleteBehavior.Cascade);
|
|
e.HasOne(m => m.Recipe).WithMany().HasForeignKey(m => m.RecipeId).OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<UserFavoriteRecipe>(e =>
|
|
{
|
|
e.HasKey(f => new { f.UserId, f.RecipeId });
|
|
e.Property(f => f.UserId).HasColumnType("uuid");
|
|
e.HasOne(f => f.Recipe).WithMany().HasForeignKey(f => f.RecipeId).OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<UserFavoriteCatalogItem>(e =>
|
|
{
|
|
e.HasKey(f => new { f.UserId, f.CatalogItemId });
|
|
e.Property(f => f.UserId).HasColumnType("uuid");
|
|
e.HasOne(f => f.CatalogItem).WithMany().HasForeignKey(f => f.CatalogItemId).OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<DietUserProfile>(e =>
|
|
{
|
|
e.HasKey(p => p.UserId);
|
|
e.Property(p => p.UserId).HasColumnType("uuid");
|
|
e.Property(p => p.HeightCm).HasColumnType("numeric(5,2)");
|
|
e.Property(p => p.WeightKg).HasColumnType("numeric(5,2)");
|
|
e.HasOne(p => p.User)
|
|
.WithMany()
|
|
.HasForeignKey(p => p.UserId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<DietGeneratorSession>(e =>
|
|
{
|
|
e.HasKey(s => s.Id);
|
|
e.Property(s => s.Id).UseIdentityByDefaultColumn();
|
|
e.Property(s => s.UserId).HasColumnType("uuid");
|
|
e.Property(s => s.ProposedProteinG).HasColumnType("numeric(6,2)");
|
|
e.Property(s => s.ProposedFatG).HasColumnType("numeric(6,2)");
|
|
e.Property(s => s.ProposedCarbsG).HasColumnType("numeric(6,2)");
|
|
e.Property(s => s.PreferencesJson).HasColumnType("jsonb");
|
|
e.HasMany(s => s.DraftMeals).WithOne(m => m.Session!).HasForeignKey(m => m.SessionId).OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<DietGeneratorDraftMeal>(e =>
|
|
{
|
|
e.HasKey(m => m.Id);
|
|
e.Property(m => m.Id).UseIdentityByDefaultColumn();
|
|
e.Property(m => m.Portions).HasColumnType("numeric(4,2)");
|
|
e.Property(m => m.ProteinG).HasColumnType("numeric(6,2)");
|
|
e.Property(m => m.FatG).HasColumnType("numeric(6,2)");
|
|
e.Property(m => m.CarbsG).HasColumnType("numeric(6,2)");
|
|
e.HasOne(m => m.Recipe).WithMany().HasForeignKey(m => m.RecipeId).OnDelete(DeleteBehavior.Cascade);
|
|
e.HasMany(m => m.PlannedIngredients).WithOne(i => i.DraftMeal!).HasForeignKey(i => i.DraftMealId)
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
});
|
|
|
|
modelBuilder.Entity<DietGeneratorDraftMealIngredient>(e =>
|
|
{
|
|
e.HasKey(i => i.Id);
|
|
e.Property(i => i.Id).UseIdentityByDefaultColumn();
|
|
e.Property(i => i.AmountGrams).HasColumnType("numeric(8,2)");
|
|
e.HasOne(i => i.SourceIngredient).WithMany().HasForeignKey(i => i.SourceIngredientId)
|
|
.OnDelete(DeleteBehavior.SetNull);
|
|
});
|
|
|
|
modelBuilder.Entity<RecipeGeneratorSession>(e =>
|
|
{
|
|
e.HasKey(s => s.Id);
|
|
e.Property(s => s.Id).UseIdentityByDefaultColumn();
|
|
e.Property(s => s.UserId).HasColumnType("uuid");
|
|
e.Property(s => s.ConstraintsJson).HasColumnType("jsonb");
|
|
e.Property(s => s.DraftJson).HasColumnType("jsonb");
|
|
e.HasOne(s => s.SavedRecipe).WithMany().HasForeignKey(s => s.SavedRecipeId).OnDelete(DeleteBehavior.SetNull);
|
|
});
|
|
}
|
|
}
|