193 lines
9.8 KiB
C#
193 lines
9.8 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|
using Tiku.Domain.Commerce;
|
|
using Tiku.Domain.Identity;
|
|
using Tiku.Domain.Learning;
|
|
using Tiku.Domain.Tenancy;
|
|
|
|
namespace Tiku.Infrastructure.Persistence.Configurations;
|
|
|
|
internal sealed class BusinessLineConfiguration : IEntityTypeConfiguration<BusinessLine>
|
|
{
|
|
public void Configure(EntityTypeBuilder<BusinessLine> builder)
|
|
{
|
|
builder.ConfigureEntity("business_lines");
|
|
builder.ConfigureTimestamps();
|
|
builder.Property(entity => entity.Code).HasMaxLength(50);
|
|
builder.Property(entity => entity.Name).HasMaxLength(100);
|
|
builder.Property(entity => entity.RegionAccessStrategy).HasSnakeCaseEnum().HasMaxLength(64);
|
|
builder.Property(entity => entity.TargetRegionCooldownDays).HasDefaultValue(30);
|
|
builder.ToTable(table => table.HasCheckConstraint(
|
|
"ck_business_lines_target_region_cooldown_days",
|
|
"target_region_cooldown_days between 0 and 365"));
|
|
builder.HasIndex(entity => entity.Code).IsUnique();
|
|
}
|
|
}
|
|
|
|
internal sealed class MarketRegionConfiguration : IEntityTypeConfiguration<MarketRegion>
|
|
{
|
|
public void Configure(EntityTypeBuilder<MarketRegion> builder)
|
|
{
|
|
builder.ConfigureEntity("market_regions");
|
|
builder.ConfigureTimestamps();
|
|
builder.Property(entity => entity.Code).HasMaxLength(50);
|
|
builder.Property(entity => entity.Name).HasMaxLength(100);
|
|
builder.Property(entity => entity.ParentCode).HasMaxLength(50);
|
|
builder.HasIndex(entity => entity.Code).IsUnique();
|
|
}
|
|
}
|
|
|
|
internal sealed class TenantLearningLicenseConfiguration : IEntityTypeConfiguration<TenantLearningLicense>
|
|
{
|
|
public void Configure(EntityTypeBuilder<TenantLearningLicense> builder)
|
|
{
|
|
builder.ConfigureTenantEntity("tenant_learning_licenses");
|
|
builder.ConfigureTimestamps();
|
|
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
|
|
builder.Property(entity => entity.Version).IsConcurrencyToken().HasDefaultValue(1L);
|
|
builder.HasIndex(entity => new { entity.TenantId, entity.BusinessLineId, entity.Status });
|
|
builder.HasIndex(entity => entity.TenantId).IsUnique().HasFilter("is_primary and status = 'active'");
|
|
builder.HasOne<BusinessLine>().WithMany().HasForeignKey(entity => entity.BusinessLineId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
}
|
|
}
|
|
|
|
internal sealed class TenantLearningLicenseRegionConfiguration : IEntityTypeConfiguration<TenantLearningLicenseRegion>
|
|
{
|
|
public void Configure(EntityTypeBuilder<TenantLearningLicenseRegion> builder)
|
|
{
|
|
builder.ConfigureEntity("tenant_learning_license_regions");
|
|
builder.HasAlternateKey(entity => new { entity.TenantId, entity.Id });
|
|
builder.HasIndex(entity => new { entity.TenantId, entity.LicenseId, entity.MarketRegionId }).IsUnique();
|
|
builder.HasOne<TenantLearningLicense>().WithMany()
|
|
.HasForeignKey(entity => new { entity.TenantId, entity.LicenseId })
|
|
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
builder.HasOne<MarketRegion>().WithMany().HasForeignKey(entity => entity.MarketRegionId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
}
|
|
}
|
|
|
|
internal sealed class LearningProductConfiguration : IEntityTypeConfiguration<LearningProduct>
|
|
{
|
|
public void Configure(EntityTypeBuilder<LearningProduct> builder)
|
|
{
|
|
builder.ConfigureTenantEntity("learning_products");
|
|
builder.ConfigureTimestamps();
|
|
builder.Property(entity => entity.Code).HasMaxLength(100);
|
|
builder.Property(entity => entity.Name).HasMaxLength(200);
|
|
builder.HasIndex(entity => new { entity.TenantId, entity.Code }).IsUnique();
|
|
builder.HasOne<BusinessLine>().WithMany().HasForeignKey(entity => entity.BusinessLineId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
}
|
|
}
|
|
|
|
internal sealed class LearningProductScopeConfiguration : IEntityTypeConfiguration<LearningProductScope>
|
|
{
|
|
public void Configure(EntityTypeBuilder<LearningProductScope> builder)
|
|
{
|
|
builder.ConfigureEntity("learning_product_scopes");
|
|
builder.HasAlternateKey(entity => new { entity.TenantId, entity.Id });
|
|
builder.HasIndex(entity => new { entity.TenantId, entity.ProductId, entity.ContentSliceId }).IsUnique();
|
|
builder.HasOne<LearningProduct>().WithMany()
|
|
.HasForeignKey(entity => new { entity.TenantId, entity.ProductId })
|
|
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
builder.HasOne<ContentSlice>().WithMany()
|
|
.HasForeignKey(entity => new { TenantId = entity.ContentSliceOwnerTenantId, Id = entity.ContentSliceId })
|
|
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
}
|
|
}
|
|
|
|
internal sealed class ContentSliceConfiguration : IEntityTypeConfiguration<ContentSlice>
|
|
{
|
|
public void Configure(EntityTypeBuilder<ContentSlice> builder)
|
|
{
|
|
builder.ConfigureTenantEntity("content_slices");
|
|
builder.ConfigureTimestamps();
|
|
builder.Property(entity => entity.RegionScope).HasSnakeCaseEnum();
|
|
builder.Property(entity => entity.ResourceType).HasSnakeCaseEnum();
|
|
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
|
|
builder.Property(entity => entity.ContentVersion).IsConcurrencyToken().HasDefaultValue(1L);
|
|
builder.HasIndex(entity => new
|
|
{
|
|
entity.TenantId,
|
|
entity.ResourceType,
|
|
entity.ResourceId,
|
|
entity.Status
|
|
});
|
|
builder.HasIndex(entity => new { entity.BusinessLineId, entity.RegionScope, entity.MarketRegionId });
|
|
builder.HasOne<BusinessLine>().WithMany().HasForeignKey(entity => entity.BusinessLineId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
builder.HasOne<MarketRegion>().WithMany().HasForeignKey(entity => entity.MarketRegionId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
builder.ToTable(table => table.HasCheckConstraint(
|
|
"ck_content_slices_region_scope",
|
|
"(region_scope = 'national' and market_region_id is null) or (region_scope = 'region' and market_region_id is not null)"));
|
|
}
|
|
}
|
|
|
|
internal sealed class StudentTargetRegionHistoryConfiguration : IEntityTypeConfiguration<StudentTargetRegionHistory>
|
|
{
|
|
public void Configure(EntityTypeBuilder<StudentTargetRegionHistory> builder)
|
|
{
|
|
builder.ConfigureTenantEntity("student_target_region_history");
|
|
builder.ConfigureTimestamps();
|
|
builder.Property(entity => entity.Reason).HasMaxLength(1000);
|
|
builder.HasIndex(entity => new { entity.TenantId, entity.UserId, entity.BusinessLineId }).IsUnique()
|
|
.HasDatabaseName("ux_student_target_region_current")
|
|
.HasFilter("is_current");
|
|
builder.HasIndex(entity => new
|
|
{
|
|
entity.TenantId,
|
|
entity.UserId,
|
|
entity.BusinessLineId,
|
|
entity.EffectiveAt
|
|
}).HasDatabaseName("ix_student_target_region_history");
|
|
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.Cascade);
|
|
builder.HasOne<BusinessLine>().WithMany().HasForeignKey(entity => entity.BusinessLineId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.ChangedBy).OnDelete(DeleteBehavior.SetNull);
|
|
builder.HasOne<MarketRegion>().WithMany().HasForeignKey(entity => entity.MarketRegionId)
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
}
|
|
}
|
|
|
|
internal sealed class ClassContentAssignmentConfiguration : IEntityTypeConfiguration<ClassContentAssignment>
|
|
{
|
|
public void Configure(EntityTypeBuilder<ClassContentAssignment> builder)
|
|
{
|
|
builder.ConfigureTenantEntity("class_content_assignments");
|
|
builder.ConfigureTimestamps();
|
|
builder.Property(entity => entity.ResourceType).HasSnakeCaseEnum();
|
|
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
|
|
builder.Property(entity => entity.RevokedReason).HasMaxLength(1000);
|
|
builder.HasIndex(entity => new { entity.TenantId, entity.ClassId, entity.Status, entity.StartsAt });
|
|
builder.HasIndex(entity => new { entity.TenantId, entity.ResourceType, entity.ResourceId, entity.Status });
|
|
builder.HasOne<TenantClass>().WithMany()
|
|
.HasForeignKey(entity => new { entity.TenantId, entity.ClassId })
|
|
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
|
|
.OnDelete(DeleteBehavior.Cascade);
|
|
builder.HasOne<ContentSlice>().WithMany()
|
|
.HasForeignKey(entity => new { TenantId = entity.ContentSliceOwnerTenantId, Id = entity.ContentSliceId })
|
|
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
|
|
.OnDelete(DeleteBehavior.Restrict);
|
|
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.CreatedBy).OnDelete(DeleteBehavior.SetNull);
|
|
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.RevokedBy).OnDelete(DeleteBehavior.SetNull);
|
|
}
|
|
}
|
|
|
|
internal sealed class LearningAccessVersionConfiguration : IEntityTypeConfiguration<LearningAccessVersion>
|
|
{
|
|
public void Configure(EntityTypeBuilder<LearningAccessVersion> builder)
|
|
{
|
|
builder.ConfigureTenantEntity("learning_access_versions");
|
|
builder.Property(entity => entity.GrantVersion).IsConcurrencyToken().HasDefaultValue(1L);
|
|
builder.Property(entity => entity.ContentVersion).HasDefaultValue(1L);
|
|
builder.Property(entity => entity.StrongRevocationVersion).HasDefaultValue(1L);
|
|
builder.HasIndex(entity => new { entity.TenantId, entity.UserId }).IsUnique();
|
|
builder.HasOne<User>().WithMany().HasForeignKey(entity => entity.UserId).OnDelete(DeleteBehavior.Cascade);
|
|
}
|
|
}
|