using MetaCourse.Api.Entities; using Microsoft.EntityFrameworkCore; namespace MetaCourse.Api.Data; public class AppDbContext(DbContextOptions options) : DbContext(options) { public DbSet Users => Set(); public DbSet Courses => Set(); public DbSet Topics => Set(); public DbSet Resources => Set(); public DbSet TopicResources => Set(); public DbSet UserCourses => Set(); public DbSet UserTopicProgresses => Set(); public DbSet UserResourceProgresses => Set(); protected override void OnModelCreating(ModelBuilder modelBuilder) { // TopicResource composite key modelBuilder.Entity() .HasKey(tr => new { tr.TopicId, tr.ResourceId }); modelBuilder.Entity() .HasOne(tr => tr.Topic) .WithMany(t => t.TopicResources) .HasForeignKey(tr => tr.TopicId); modelBuilder.Entity() .HasOne(tr => tr.Resource) .WithMany(r => r.TopicResources) .HasForeignKey(tr => tr.ResourceId); // UserCourse composite key modelBuilder.Entity() .HasKey(uc => new { uc.UserId, uc.CourseId }); modelBuilder.Entity() .HasOne(uc => uc.User) .WithMany(u => u.UserCourses) .HasForeignKey(uc => uc.UserId); modelBuilder.Entity() .HasOne(uc => uc.Course) .WithMany(c => c.UserCourses) .HasForeignKey(uc => uc.CourseId); // UserTopicProgress composite key modelBuilder.Entity() .HasKey(utp => new { utp.UserId, utp.TopicId }); modelBuilder.Entity() .HasOne(utp => utp.User) .WithMany(u => u.TopicProgresses) .HasForeignKey(utp => utp.UserId); modelBuilder.Entity() .HasOne(utp => utp.Topic) .WithMany(t => t.UserProgresses) .HasForeignKey(utp => utp.TopicId); // UserResourceProgress composite key modelBuilder.Entity() .HasKey(urp => new { urp.UserId, urp.ResourceId }); modelBuilder.Entity() .HasOne(urp => urp.User) .WithMany(u => u.ResourceProgresses) .HasForeignKey(urp => urp.UserId); modelBuilder.Entity() .HasOne(urp => urp.Resource) .WithMany(r => r.UserProgresses) .HasForeignKey(urp => urp.ResourceId); // Unique email modelBuilder.Entity() .HasIndex(u => u.Email) .IsUnique(); // Course -> Creator (restrict delete to avoid cascade) modelBuilder.Entity() .HasOne(c => c.Creator) .WithMany(u => u.CreatedCourses) .HasForeignKey(c => c.CreatorId) .OnDelete(DeleteBehavior.Restrict); // Enum stored as string modelBuilder.Entity() .Property(c => c.Status) .HasConversion(); modelBuilder.Entity() .Property(r => r.Type) .HasConversion(); SeedData(modelBuilder); } private static void SeedData(ModelBuilder modelBuilder) { var userId1 = Guid.Parse("11111111-1111-1111-1111-111111111111"); var userId2 = Guid.Parse("22222222-2222-2222-2222-222222222222"); var courseId1 = Guid.Parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"); var courseId2 = Guid.Parse("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"); var topicId1 = Guid.Parse("cccccccc-cccc-cccc-cccc-cccccccccccc"); var topicId2 = Guid.Parse("dddddddd-dddd-dddd-dddd-dddddddddddd"); var topicId3 = Guid.Parse("eeeeeeee-eeee-eeee-eeee-eeeeeeeeeeee"); var resourceId1 = Guid.Parse("ffffffff-ffff-ffff-ffff-ffffffffffff"); var resourceId2 = Guid.Parse("00000000-0000-0000-aaaa-000000000001"); var resourceId3 = Guid.Parse("00000000-0000-0000-aaaa-000000000002"); var now = new DateTime(2025, 1, 1, 0, 0, 0, DateTimeKind.Utc); modelBuilder.Entity().HasData( new User { Id = userId1, Name = "Alice Dupont", Email = "alice@metacourse.io", PasswordHash = "$2a$11$EuQ5pngrcHnxS6BhcMo6Mut73tAaJSDYB7K9TxahwJa5wAnJCF2o6", CreatedAt = now }, new User { Id = userId2, Name = "Bob Martin", Email = "bob@metacourse.io", PasswordHash = "$2a$11$4.r72zZul8Pj.QJ5kmVNE.0dRJuAmIefGvZtt9xZ1.fAzztjGKqtS", CreatedAt = now } ); modelBuilder.Entity().HasData( new Course { Id = courseId1, Title = "Développement Web Moderne avec React", Description = "Maîtrisez React, Tailwind CSS et TypeScript pour créer des applications web performantes.", Status = CourseStatus.Published, CreatorId = userId1, CreatedAt = now, UpdatedAt = now }, new Course { Id = courseId2, Title = "API REST avec .NET et FastEndpoints", Description = "Apprenez à construire des APIs REST robustes avec ASP.NET Core et FastEndpoints.", Status = CourseStatus.Draft, CreatorId = userId2, CreatedAt = now, UpdatedAt = now } ); modelBuilder.Entity().HasData( new Topic { Id = topicId1, Title = "Introduction à React", Description = "Les bases de React : composants, JSX, props.", Position = 1, CourseId = courseId1 }, new Topic { Id = topicId2, Title = "Hooks et State", Description = "useState, useEffect et hooks personnalisés.", Position = 2, CourseId = courseId1 }, new Topic { Id = topicId3, Title = "Fondamentaux REST", Description = "Principes REST et verbes HTTP.", Position = 1, CourseId = courseId2 } ); modelBuilder.Entity().HasData( new Resource { Id = resourceId1, Type = ResourceType.Video, Title = "React en 30 minutes", Content = "https://youtube.com/watch?v=example1", CreatedAt = now }, new Resource { Id = resourceId2, Type = ResourceType.Text, Title = "Guide des Hooks", Content = "Les hooks permettent d'utiliser le state et d'autres fonctionnalités React dans des composants fonctionnels.", CreatedAt = now }, new Resource { Id = resourceId3, Type = ResourceType.Url, Title = "Documentation officielle React", Content = "https://react.dev", CreatedAt = now } ); modelBuilder.Entity().HasData( new TopicResource { TopicId = topicId1, ResourceId = resourceId1, Position = 1 }, new TopicResource { TopicId = topicId1, ResourceId = resourceId3, Position = 2 }, new TopicResource { TopicId = topicId2, ResourceId = resourceId2, Position = 1 } ); modelBuilder.Entity().HasData( new UserCourse { UserId = userId2, CourseId = courseId1, EnrolledAt = now } ); } }