Files
tiku-backend.net/Tiku.Infrastructure/Persistence/Configurations/ContentV2ReleaseConfigurations.cs
xiong 3f5957d744
Some checks failed
ci / release-gate (push) Has been cancelled
feat(content): establish v2 learning delivery foundation
2026-08-06 09:52:18 +08:00

239 lines
12 KiB
C#

using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Tiku.Domain.Content;
using Tiku.Domain.Learning;
namespace Tiku.Infrastructure.Persistence.Configurations;
internal sealed class ContentReleaseConfiguration : IEntityTypeConfiguration<ContentRelease>
{
public void Configure(EntityTypeBuilder<ContentRelease> builder)
{
builder.ConfigureTenantEntity("content_releases");
builder.ConfigureTimestamps();
builder.Property(entity => entity.Name).HasMaxLength(300);
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.Property(entity => entity.CompilerVersion).HasMaxLength(100);
builder.Property(entity => entity.SourceFingerprint).HasMaxLength(64);
builder.HasIndex(entity => new { entity.TenantId, entity.CurriculumVersionId, entity.ReleaseNo }).IsUnique();
builder.HasIndex(entity => new { entity.TenantId, entity.BusinessLineId, entity.Status, entity.PublishedAt });
builder.HasOne<BusinessLine>().WithMany().HasForeignKey(entity => entity.BusinessLineId)
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<CurriculumVersion>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.CurriculumVersionId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
}
}
internal sealed class AudienceSegmentConfiguration : IEntityTypeConfiguration<AudienceSegment>
{
public void Configure(EntityTypeBuilder<AudienceSegment> builder)
{
builder.ConfigureTenantOwned("audience_segments");
builder.Property(entity => entity.RuleHash).HasMaxLength(64);
builder.HasIndex(entity => new { entity.TenantId, entity.ContentReleaseId, entity.RuleHash }).IsUnique();
builder.HasIndex(entity => new { entity.TenantId, entity.ContentReleaseId, entity.SegmentOrdinal }).IsUnique();
builder.HasOne<ContentRelease>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.ContentReleaseId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Cascade);
}
}
internal sealed class AudienceSegmentMemberConfiguration : IEntityTypeConfiguration<AudienceSegmentMember>
{
public void Configure(EntityTypeBuilder<AudienceSegmentMember> builder)
{
builder.ConfigureTenantOwned("audience_segment_members");
builder.HasIndex(entity => new
{
entity.TenantId,
entity.ContentReleaseId,
entity.AudienceSegmentId,
entity.ExamTargetProfileVersionId
}).IsUnique();
builder.HasIndex(entity => new
{
entity.TenantId,
entity.ContentReleaseId,
entity.ExamTargetProfileVersionId,
entity.AudienceSegmentId
});
builder.HasOne<AudienceSegment>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.AudienceSegmentId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne<ExamTargetProfileVersion>().WithMany()
.HasForeignKey(entity => entity.ExamTargetProfileVersionId)
.OnDelete(DeleteBehavior.Restrict);
}
}
internal sealed class ContentReleaseQuestionConfiguration : IEntityTypeConfiguration<ContentReleaseQuestion>
{
public void Configure(EntityTypeBuilder<ContentReleaseQuestion> builder)
{
builder.ConfigureTenantOwned("content_release_questions");
builder.Property(entity => entity.QuestionType).HasMaxLength(50);
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.HasIndex(entity => new
{
entity.TenantId,
entity.ContentReleaseId,
entity.AudienceSegmentId,
entity.CurriculumNodeId,
entity.Ordinal
}).IsUnique();
builder.HasIndex(entity => new
{
entity.TenantId,
entity.ContentReleaseId,
entity.AudienceSegmentId,
entity.CurriculumNodeId,
entity.Status,
entity.Difficulty,
entity.QuestionType,
entity.Ordinal
}).HasDatabaseName("ix_content_release_question_candidates");
builder.HasOne<ContentRelease>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.ContentReleaseId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne<AudienceSegment>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.AudienceSegmentId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<QuestionPlacement>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.QuestionPlacementId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<QuestionRevision>().WithMany()
.HasForeignKey(entity => new
{
TenantId = entity.QuestionAssetOwnerTenantId,
entity.QuestionAssetId,
Id = entity.QuestionRevisionId
})
.HasPrincipalKey(entity => new { entity.TenantId, entity.QuestionAssetId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<AssessmentPolicyVersion>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.AssessmentPolicyVersionId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
}
}
internal sealed class CollectionReleaseConfiguration : IEntityTypeConfiguration<CollectionRelease>
{
public void Configure(EntityTypeBuilder<CollectionRelease> builder)
{
builder.ConfigureTenantEntity("collection_releases");
builder.ConfigureTimestamps();
builder.Property(entity => entity.Name).HasMaxLength(300);
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.HasIndex(entity => new { entity.TenantId, entity.SourceCollectionId, entity.VersionNo }).IsUnique();
builder.HasOne<ContentRelease>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.ContentReleaseId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
}
}
internal sealed class CollectionReleaseQuestionConfiguration : IEntityTypeConfiguration<CollectionReleaseQuestion>
{
public void Configure(EntityTypeBuilder<CollectionReleaseQuestion> builder)
{
builder.ConfigureTenantOwned("collection_release_questions");
builder.HasIndex(entity => new { entity.TenantId, entity.CollectionReleaseId, entity.SortOrder })
.HasDatabaseName("ux_collection_release_question_order")
.IsUnique();
builder.HasIndex(entity => new
{
entity.TenantId,
entity.CollectionReleaseId,
entity.ContentReleaseQuestionId
}).HasDatabaseName("ux_collection_release_question_item").IsUnique();
builder.HasOne<CollectionRelease>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.CollectionReleaseId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Cascade);
builder.HasOne<ContentReleaseQuestion>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.ContentReleaseQuestionId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
}
}
internal sealed class BlueprintReleaseConfiguration : IEntityTypeConfiguration<BlueprintRelease>
{
public void Configure(EntityTypeBuilder<BlueprintRelease> builder)
{
builder.ConfigureTenantEntity("blueprint_releases");
builder.ConfigureTimestamps();
builder.Property(entity => entity.Name).HasMaxLength(300);
builder.Property(entity => entity.AssemblyRules).IsJson("{}");
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.HasIndex(entity => new { entity.TenantId, entity.SourceBlueprintId, entity.VersionNo }).IsUnique();
builder.HasOne<ContentRelease>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.ContentReleaseId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<CollectionRelease>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.CollectionReleaseId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
builder.HasOne<ExamPaperSpecificationVersion>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.ExamPaperSpecificationVersionId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
}
}
internal sealed class PlatformContentPackageVersionConfiguration :
IEntityTypeConfiguration<PlatformContentPackageVersion>
{
public void Configure(EntityTypeBuilder<PlatformContentPackageVersion> builder)
{
builder.ConfigureTenantEntity("platform_content_package_versions");
builder.ConfigureTimestamps();
builder.Property(entity => entity.PackageCode).HasMaxLength(100);
builder.Property(entity => entity.ContentHash).HasMaxLength(64);
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.HasIndex(entity => new { entity.TenantId, entity.PackageCode, entity.VersionNo }).IsUnique();
builder.HasIndex(entity => new { entity.TenantId, entity.ContentHash }).IsUnique();
builder.HasOne<ContentRelease>().WithMany()
.HasForeignKey(entity => new { entity.TenantId, Id = entity.ContentReleaseId })
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Restrict);
}
}
internal sealed class PlatformContentPackageCellProjectionConfiguration :
IEntityTypeConfiguration<PlatformContentPackageCellProjection>
{
public void Configure(EntityTypeBuilder<PlatformContentPackageCellProjection> builder)
{
builder.ConfigureEntity("platform_content_package_cell_projections");
builder.Property(entity => entity.PackageCode).HasMaxLength(100);
builder.Property(entity => entity.CellId).HasMaxLength(100);
builder.Property(entity => entity.ContentHash).HasMaxLength(64);
builder.Property(entity => entity.Status).HasSnakeCaseEnum();
builder.Property(entity => entity.LastError).HasMaxLength(2000);
builder.HasIndex(entity => new { entity.PackageOwnerTenantId, entity.PackageCode, entity.CellId })
.HasDatabaseName("ux_platform_package_cell_cursor").IsUnique();
builder.HasIndex(entity => new { entity.PlatformContentPackageVersionId, entity.CellId })
.HasDatabaseName("ix_platform_package_cell_version");
builder.HasIndex(entity => new { entity.PackageOwnerTenantId, entity.PlatformContentPackageVersionId })
.HasDatabaseName("ix_platform_package_cell_owner_version");
builder.HasOne<PlatformContentPackageVersion>().WithMany()
.HasForeignKey(entity => new
{
TenantId = entity.PackageOwnerTenantId,
Id = entity.PlatformContentPackageVersionId
})
.HasPrincipalKey(entity => new { entity.TenantId, entity.Id })
.OnDelete(DeleteBehavior.Cascade);
}
}