diff --git a/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.Designer.cs b/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.Designer.cs new file mode 100644 index 0000000..560b81f --- /dev/null +++ b/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.Designer.cs @@ -0,0 +1,130 @@ +// +using System; +using CvMatcher.Data; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; + +#nullable disable + +namespace CvMatcher.Data.Migrations +{ + [DbContext(typeof(CvMatcherDbContext))] + [Migration("20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage")] + partial class UpdateResultsUniqueConstraintToIncludeLanguage + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("cvMatcher") + .HasAnnotation("ProductVersion", "10.0.7") + .HasAnnotation("Relational:MaxIdentifierLength", 128); + + SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder); + + modelBuilder.Entity("CvMatcher.Data.Entities.AiPromptEntity", b => + { + b.Property("Key") + .HasMaxLength(128) + .HasColumnType("nvarchar(128)"); + + b.Property("Language") + .HasMaxLength(8) + .HasColumnType("nvarchar(8)"); + + b.Property("Description") + .IsRequired() + .ValueGeneratedOnAdd() + .HasMaxLength(500) + .HasColumnType("nvarchar(500)") + .HasDefaultValue(""); + + b.Property("UpdatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("SYSUTCDATETIME()"); + + b.Property("Value") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.HasKey("Key", "Language"); + + b.ToTable("AiPrompts", "cvMatcher"); + }); + + modelBuilder.Entity("CvMatcher.Data.Entities.CvMatchResultEntity", b => + { + b.Property("Id") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("SYSUTCDATETIME()"); + + b.Property("CvDocumentId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("JobDocumentId") + .IsRequired() + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("Language") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("ResultJson") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Score") + .HasColumnType("int"); + + b.HasKey("Id"); + + b.HasIndex("CvDocumentId", "JobDocumentId", "Language") + .IsUnique(); + + b.ToTable("Results", "cvMatcher"); + }); + + modelBuilder.Entity("CvMatcher.Data.Entities.CvMatcherChatCacheEntity", b => + { + b.Property("CacheKey") + .HasMaxLength(64) + .HasColumnType("nvarchar(64)"); + + b.Property("CreatedAt") + .ValueGeneratedOnAdd() + .HasColumnType("datetime2") + .HasDefaultValueSql("SYSUTCDATETIME()"); + + b.Property("Model") + .IsRequired() + .HasMaxLength(120) + .HasColumnType("nvarchar(120)"); + + b.Property("ResponseText") + .IsRequired() + .HasColumnType("nvarchar(max)"); + + b.Property("Temperature") + .HasColumnType("decimal(4,2)"); + + b.HasKey("CacheKey"); + + b.ToTable("ChatCache", "cvMatcher"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.cs b/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.cs new file mode 100644 index 0000000..550b5bd --- /dev/null +++ b/Apis/cv-matcher-data/Migrations/20260529111000_UpdateResultsUniqueConstraintToIncludeLanguage.cs @@ -0,0 +1,46 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace CvMatcher.Data.Migrations +{ + /// + public partial class UpdateResultsUniqueConstraintToIncludeLanguage : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + // The Language column was added in migration 20260524140335, but the unique constraint + // was never updated from (CvDocumentId, JobDocumentId) to include Language. + // This caused duplicate key violations when matching the same CV+Job in different languages. + + migrationBuilder.DropIndex( + name: "IX_Results_CvDocumentId_JobDocumentId", + schema: MigrationConstants.SchemaName, + table: "Results"); + + migrationBuilder.CreateIndex( + name: "IX_Results_CvDocumentId_JobDocumentId_Language", + schema: MigrationConstants.SchemaName, + table: "Results", + columns: new[] { "CvDocumentId", "JobDocumentId", "Language" }, + unique: true); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropIndex( + name: "IX_Results_CvDocumentId_JobDocumentId_Language", + schema: MigrationConstants.SchemaName, + table: "Results"); + + migrationBuilder.CreateIndex( + name: "IX_Results_CvDocumentId_JobDocumentId", + schema: MigrationConstants.SchemaName, + table: "Results", + columns: new[] { "CvDocumentId", "JobDocumentId" }, + unique: true); + } + } +} diff --git a/Apis/cv-matcher-data/Migrations/CvMatcherDbContextModelSnapshot.cs b/Apis/cv-matcher-data/Migrations/CvMatcherDbContextModelSnapshot.cs index 33937c3..5e2fe70 100644 --- a/Apis/cv-matcher-data/Migrations/CvMatcherDbContextModelSnapshot.cs +++ b/Apis/cv-matcher-data/Migrations/CvMatcherDbContextModelSnapshot.cs @@ -88,7 +88,7 @@ namespace CvMatcher.Data.Migrations b.HasKey("Id"); - b.HasIndex("CvDocumentId", "JobDocumentId") + b.HasIndex("CvDocumentId", "JobDocumentId", "Language") .IsUnique(); b.ToTable("Results", "cvMatcher");