Files
MetaCourseApi/MetaCourse.Api/Data/AppDbContext.cs
T
2026-05-05 10:39:43 +02:00

183 lines
7.4 KiB
C#

using MetaCourse.Api.Entities;
using Microsoft.EntityFrameworkCore;
namespace MetaCourse.Api.Data;
public class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{
public DbSet<User> Users => Set<User>();
public DbSet<Course> Courses => Set<Course>();
public DbSet<Topic> Topics => Set<Topic>();
public DbSet<Resource> Resources => Set<Resource>();
public DbSet<TopicResource> TopicResources => Set<TopicResource>();
public DbSet<UserCourse> UserCourses => Set<UserCourse>();
public DbSet<UserTopicProgress> UserTopicProgresses => Set<UserTopicProgress>();
public DbSet<UserResourceProgress> UserResourceProgresses => Set<UserResourceProgress>();
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// TopicResource composite key
modelBuilder.Entity<TopicResource>()
.HasKey(tr => new { tr.TopicId, tr.ResourceId });
modelBuilder.Entity<TopicResource>()
.HasOne(tr => tr.Topic)
.WithMany(t => t.TopicResources)
.HasForeignKey(tr => tr.TopicId);
modelBuilder.Entity<TopicResource>()
.HasOne(tr => tr.Resource)
.WithMany(r => r.TopicResources)
.HasForeignKey(tr => tr.ResourceId);
// UserCourse composite key
modelBuilder.Entity<UserCourse>()
.HasKey(uc => new { uc.UserId, uc.CourseId });
modelBuilder.Entity<UserCourse>()
.HasOne(uc => uc.User)
.WithMany(u => u.UserCourses)
.HasForeignKey(uc => uc.UserId);
modelBuilder.Entity<UserCourse>()
.HasOne(uc => uc.Course)
.WithMany(c => c.UserCourses)
.HasForeignKey(uc => uc.CourseId);
// UserTopicProgress composite key
modelBuilder.Entity<UserTopicProgress>()
.HasKey(utp => new { utp.UserId, utp.TopicId });
modelBuilder.Entity<UserTopicProgress>()
.HasOne(utp => utp.User)
.WithMany(u => u.TopicProgresses)
.HasForeignKey(utp => utp.UserId);
modelBuilder.Entity<UserTopicProgress>()
.HasOne(utp => utp.Topic)
.WithMany(t => t.UserProgresses)
.HasForeignKey(utp => utp.TopicId);
// UserResourceProgress composite key
modelBuilder.Entity<UserResourceProgress>()
.HasKey(urp => new { urp.UserId, urp.ResourceId });
modelBuilder.Entity<UserResourceProgress>()
.HasOne(urp => urp.User)
.WithMany(u => u.ResourceProgresses)
.HasForeignKey(urp => urp.UserId);
modelBuilder.Entity<UserResourceProgress>()
.HasOne(urp => urp.Resource)
.WithMany(r => r.UserProgresses)
.HasForeignKey(urp => urp.ResourceId);
// Unique email
modelBuilder.Entity<User>()
.HasIndex(u => u.Email)
.IsUnique();
// Course -> Creator (restrict delete to avoid cascade)
modelBuilder.Entity<Course>()
.HasOne(c => c.Creator)
.WithMany(u => u.CreatedCourses)
.HasForeignKey(c => c.CreatorId)
.OnDelete(DeleteBehavior.Restrict);
// Enum stored as string
modelBuilder.Entity<Course>()
.Property(c => c.Status)
.HasConversion<string>();
modelBuilder.Entity<Resource>()
.Property(r => r.Type)
.HasConversion<string>();
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<User>().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<Course>().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<Topic>().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<Resource>().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<TopicResource>().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<UserCourse>().HasData(
new UserCourse { UserId = userId2, CourseId = courseId1, EnrolledAt = now }
);
}
}