Files
tiku-backend.net/Tiku.Infrastructure/Persistence/Configurations/LearningAccessConfigurations.cs

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);
}
}