using Microsoft.EntityFrameworkCore; using BimAI.Domain.Entities; namespace BimAI.Infrastructure.Data; public class BimAIDbContext(DbContextOptions options) : DbContext(options) { public DbSet Products { get; set; } public DbSet Invoices { get; set; } public DbSet SyncStates { get; set; } public DbSet Users { get; set; } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); // Product properties modelBuilder.Entity().HasKey(x => x.Id); modelBuilder.Entity().Property(x => x.Name).IsRequired().HasMaxLength(512); modelBuilder.Entity().Property(x => x.Code).IsRequired().HasMaxLength(40); modelBuilder.Entity().Property(x => x.Ean).IsRequired().HasMaxLength(50); modelBuilder.Entity().Property(x => x.StockAddresses).IsRequired().HasMaxLength(512); // Invoice properties modelBuilder.Entity().HasKey(x => x.Id); modelBuilder.Entity().Property(x => x.DocumentNo).IsRequired().HasMaxLength(100); modelBuilder.Entity().Property(x => x.Type).IsRequired().HasMaxLength(50); modelBuilder.Entity().Property(x => x.ClientName).IsRequired().HasMaxLength(255); modelBuilder.Entity().Property(x => x.ClientId).HasMaxLength(100); modelBuilder.Entity().Property(x => x.ClientNip).HasMaxLength(50); modelBuilder.Entity().Property(x => x.ClientAddress).HasMaxLength(500); modelBuilder.Entity().Property(x => x.Currency).IsRequired().HasMaxLength(10); modelBuilder.Entity().Property(x => x.Source).IsRequired().HasMaxLength(50); modelBuilder.Entity().Property(x => x.TotalNetto).HasPrecision(18, 2); modelBuilder.Entity().Property(x => x.TotalBrutto).HasPrecision(18, 2); modelBuilder.Entity().Property(x => x.TotalVat).HasPrecision(18, 2); modelBuilder.Entity().HasIndex(x => new { x.DocumentNo, x.Source }).IsUnique().HasDatabaseName("IX_Invoices_DocumentNo_Source"); // SyncState properties modelBuilder.Entity().HasKey((x => x.Entity)); // User properties modelBuilder.Entity().HasKey(x => x.Id); modelBuilder.Entity().Property(x => x.GoogleId).IsRequired().HasMaxLength(100); modelBuilder.Entity().Property(x => x.Email).IsRequired().HasMaxLength(255); modelBuilder.Entity().Property(x => x.FullName).IsRequired().HasMaxLength(255); modelBuilder.Entity().Property(x => x.IsActive).IsRequired().HasDefaultValue(false); modelBuilder.Entity().Property(x => x.LastLoginAt).IsRequired(false); // User indexes modelBuilder.Entity().HasIndex(x => x.GoogleId).IsUnique().HasDatabaseName("IX_Users_GoogleId"); modelBuilder.Entity().HasIndex(x => x.Email).IsUnique().HasDatabaseName("IX_Users_Email"); // Configure defaults for all CreatedAt and UpdatedAt in entities ConfigureBaseEntity(modelBuilder); } private void ConfigureBaseEntity(ModelBuilder modelBuilder) { foreach (var entityType in modelBuilder.Model.GetEntityTypes()) { if (typeof(BaseEntity).IsAssignableFrom(entityType.ClrType)) { modelBuilder.Entity(entityType.ClrType) .Property(nameof(BaseEntity.CreatedAt)) .HasDefaultValueSql("GETUTCDATE()"); modelBuilder.Entity(entityType.ClrType) .Property(nameof(BaseEntity.UpdatedAt)) .HasDefaultValueSql("GETUTCDATE()"); } } } public override int SaveChanges() { UpdateTimestamps(); return base.SaveChanges(); } public override Task SaveChangesAsync(CancellationToken cancellationToken = default) { UpdateTimestamps(); return base.SaveChangesAsync(cancellationToken); } private void UpdateTimestamps() { var entities = ChangeTracker.Entries(); foreach (var entity in entities) { if (entity.State == EntityState.Added) { entity.Entity.CreatedAt = DateTime.UtcNow; entity.Entity.UpdatedAt = DateTime.UtcNow; break; } else if (entity.State == EntityState.Modified) { entity.Entity.UpdatedAt = DateTime.UtcNow; break; } } } }