Compare commits

...

5 commits
v1.0.19 ... dev

Author SHA1 Message Date
Suphonchai Phoonsawat
44c56c4a0a แก้ error insert score
All checks were successful
Build & Deploy on Dev / build (push) Successful in 45s
2026-05-19 17:37:42 +07:00
Suphonchai Phoonsawat
d019ed588b fix relation
All checks were successful
Build & Deploy on Dev / build (push) Successful in 41s
2026-05-19 17:23:36 +07:00
Suphonchai Phoonsawat
054ef81c63 update model and fix code
All checks were successful
Build & Deploy on Dev / build (push) Successful in 44s
2026-05-19 17:14:39 +07:00
Suphonchai Phoonsawat
9c353f40c6 fix fk
All checks were successful
Build & Deploy on Dev / build (push) Successful in 43s
2026-05-19 17:07:27 +07:00
Suphonchai Phoonsawat
cba16f25b9 fix scoreimport
All checks were successful
Build & Deploy on Dev / build (push) Successful in 46s
2026-05-19 17:02:53 +07:00
7 changed files with 1707 additions and 13 deletions

View file

@ -20,6 +20,7 @@ namespace BMA.EHR.Recruit.Data
modelBuilder.Entity<Models.Recruits.Recruit>().HasMany(x => x.Addresses).WithOne(x => x.Recruit).OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity<Models.Recruits.Recruit>().HasMany(x => x.Addresses).WithOne(x => x.Recruit).OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Models.Recruits.Recruit>().HasMany(x => x.Certificates).WithOne(x => x.Recruit).OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity<Models.Recruits.Recruit>().HasMany(x => x.Certificates).WithOne(x => x.Recruit).OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<Models.Recruits.Recruit>().HasMany(x => x.Payments).WithOne(x => x.Recruit).OnDelete(DeleteBehavior.Cascade); modelBuilder.Entity<Models.Recruits.Recruit>().HasMany(x => x.Payments).WithOne(x => x.Recruit).OnDelete(DeleteBehavior.Cascade);
modelBuilder.Entity<ScoreImport>().HasMany(x => x.Scores).WithOne(x => x.ScoreImport).HasForeignKey(x => x.ScoreImportId).OnDelete(DeleteBehavior.Cascade);
} }
public DbSet<Document> Documents { get; set; } public DbSet<Document> Documents { get; set; }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,64 @@
using System;
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace BMA.EHR.Recruit.Migrations
{
/// <inheritdoc />
public partial class fixrelation : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_ScoreImports_Documents_ImportFileId",
table: "ScoreImports");
migrationBuilder.AlterColumn<Guid>(
name: "ImportFileId",
table: "ScoreImports",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AddForeignKey(
name: "FK_ScoreImports_Documents_ImportFileId",
table: "ScoreImports",
column: "ImportFileId",
principalTable: "Documents",
principalColumn: "Id");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_ScoreImports_Documents_ImportFileId",
table: "ScoreImports");
migrationBuilder.AlterColumn<Guid>(
name: "ImportFileId",
table: "ScoreImports",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AddForeignKey(
name: "FK_ScoreImports_Documents_ImportFileId",
table: "ScoreImports",
column: "ImportFileId",
principalTable: "Documents",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}
}

View file

@ -1353,7 +1353,7 @@ namespace BMA.EHR.Recruit.Migrations
.HasColumnOrder(101) .HasColumnOrder(101)
.HasComment("User Id ที่สร้างข้อมูล"); .HasComment("User Id ที่สร้างข้อมูล");
b.Property<Guid>("ImportFileId") b.Property<Guid?>("ImportFileId")
.HasColumnType("char(36)"); .HasColumnType("char(36)");
b.Property<string>("LastUpdateFullName") b.Property<string>("LastUpdateFullName")
@ -1550,9 +1550,7 @@ namespace BMA.EHR.Recruit.Migrations
{ {
b.HasOne("BMA.EHR.Recruit.Models.Documents.Document", "ImportFile") b.HasOne("BMA.EHR.Recruit.Models.Documents.Document", "ImportFile")
.WithMany() .WithMany()
.HasForeignKey("ImportFileId") .HasForeignKey("ImportFileId");
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.HasOne("BMA.EHR.Recruit.Models.Recruits.RecruitImport", "RecruitImport") b.HasOne("BMA.EHR.Recruit.Models.Recruits.RecruitImport", "RecruitImport")
.WithOne("ScoreImport") .WithOne("ScoreImport")

View file

@ -1,5 +1,6 @@
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace BMA.EHR.Recruit.Models.Recruits namespace BMA.EHR.Recruit.Models.Recruits
{ {
@ -83,6 +84,9 @@ namespace BMA.EHR.Recruit.Models.Recruits
[MaxLength(50), Comment("สถานะคัดกรองคุณสมบัติ")] [MaxLength(50), Comment("สถานะคัดกรองคุณสมบัติ")]
public string ExamAttribute { get; set; } = string.Empty; public string ExamAttribute { get; set; } = string.Empty;
[ForeignKey("ScoreImport")]
public Guid ScoreImportId { get; set; }
public ScoreImport ScoreImport { get; set; } public ScoreImport ScoreImport { get; set; }
} }
} }

View file

@ -7,7 +7,9 @@ namespace BMA.EHR.Recruit.Models.Recruits
{ {
public int Year { get; set; } public int Year { get; set; }
public Document ImportFile { get; set; } = new Document(); public Guid? ImportFileId { get; set; }
public Document ImportFile { get; set; }
public virtual List<RecruitScore> Scores { get; set; } = new List<RecruitScore>(); public virtual List<RecruitScore> Scores { get; set; } = new List<RecruitScore>();

View file

@ -572,12 +572,21 @@ public class ImportBackgroundService : BackgroundService
var rec_import_id = rec_import.Id; var rec_import_id = rec_import.Id;
var rec_import_year = rec_import.Year; var rec_import_year = rec_import.Year;
var hasExistingScores = rec_import.ScoreImport != null && rec_import.ScoreImport.Scores != null; var existingScoreImport = rec_import.ScoreImport;
if (hasExistingScores) if (existingScoreImport != null)
{ {
var existingScores = rec_import.ScoreImport.Scores.ToList(); var existingScores = existingScoreImport.Scores?.ToList() ?? new List<RecruitScore>();
await _context.BulkDeleteAsync(existingScores); if (existingScores.Count > 0)
await _context.BulkDeleteAsync(existingScores);
// Also delete the ScoreImport row itself (has unique index on RecruitImportId)
// Use Remove+SaveChanges instead of BulkDelete since BulkDelete fails with detached entities
var scoreImportToDelete = existingScoreImport;
_context.ChangeTracker.Clear();
var deleteStub = new ScoreImport { Id = scoreImportToDelete.Id };
_context.ScoreImports.Attach(deleteStub);
_context.ScoreImports.Remove(deleteStub);
await _context.SaveChangesAsync();
} }
// Clear tracker to avoid stale references after BulkDelete (which bypasses EF tracking) // Clear tracker to avoid stale references after BulkDelete (which bypasses EF tracking)
@ -598,7 +607,9 @@ public class ImportBackgroundService : BackgroundService
// get doc from minio (MinIOService already saves Document to its own context) // get doc from minio (MinIOService already saves Document to its own context)
var doc = await _minioService.UploadFileAsync(new DummyFormFile(job.ImportFile)); var doc = await _minioService.UploadFileAsync(new DummyFormFile(job.ImportFile));
var scoreImport_id = Guid.NewGuid(); // Pre-generate Id to use as FK
var imported = new ScoreImport(); var imported = new ScoreImport();
imported.Id = scoreImport_id;
imported.Year = rec_import_year; imported.Year = rec_import_year;
imported.RecruitImportId = rec_import_id; imported.RecruitImportId = rec_import_id;
imported.CreatedAt = DateTime.Now; imported.CreatedAt = DateTime.Now;
@ -609,9 +620,9 @@ public class ImportBackgroundService : BackgroundService
imported.LastUpdateFullName = job.FullName ?? "System Administrator"; imported.LastUpdateFullName = job.FullName ?? "System Administrator";
imported.Scores = new List<RecruitScore>(); imported.Scores = new List<RecruitScore>();
// Save ScoreImport — use shadow FK for ImportFile to avoid re-inserting Document // Save ScoreImport — set ImportFileId FK directly (explicit property, not shadow)
var scoreEntry = _context.ScoreImports.Add(imported); imported.ImportFileId = doc.Id;
scoreEntry.Property("ImportFileId").CurrentValue = doc.Id; _context.ScoreImports.Add(imported);
await _context.SaveChangesAsync(); await _context.SaveChangesAsync();
_context.ChangeTracker.Clear(); _context.ChangeTracker.Clear();
@ -653,6 +664,7 @@ public class ImportBackgroundService : BackgroundService
if (string.IsNullOrEmpty(cell1)) break; if (string.IsNullOrEmpty(cell1)) break;
var r = new RecruitScore(); var r = new RecruitScore();
r.Id = Guid.NewGuid();
r.ExamId = reader.GetValue(1)?.ToString(); r.ExamId = reader.GetValue(1)?.ToString();
if (!string.IsNullOrEmpty(r.ExamId) && recruitsDict.TryGetValue(r.ExamId, out var recruit)) if (!string.IsNullOrEmpty(r.ExamId) && recruitsDict.TryGetValue(r.ExamId, out var recruit))
@ -695,7 +707,6 @@ public class ImportBackgroundService : BackgroundService
r.LastUpdatedAt = DateTime.Now; r.LastUpdatedAt = DateTime.Now;
r.LastUpdateUserId = job.UserId ?? ""; r.LastUpdateUserId = job.UserId ?? "";
r.LastUpdateFullName = job.FullName ?? "System Administrator"; r.LastUpdateFullName = job.FullName ?? "System Administrator";
r.ScoreImport = imported;
batchScores.Add(r); batchScores.Add(r);
} }
@ -705,6 +716,11 @@ public class ImportBackgroundService : BackgroundService
if (batchCount >= batchSize) if (batchCount >= batchSize)
{ {
// Set ScoreImportId FK for all scores in batch
foreach (var score in batchScores)
{
score.ScoreImportId = scoreImport_id;
}
await _context.BulkInsertAsync(batchScores); await _context.BulkInsertAsync(batchScores);
batchScores.Clear(); batchScores.Clear();
batchCount = 0; batchCount = 0;
@ -715,6 +731,10 @@ public class ImportBackgroundService : BackgroundService
// Process remaining records // Process remaining records
if (batchScores.Count > 0) if (batchScores.Count > 0)
{ {
foreach (var score in batchScores)
{
score.ScoreImportId = scoreImport_id;
}
await _context.BulkInsertAsync(batchScores); await _context.BulkInsertAsync(batchScores);
} }
} while (reader.NextResult()); } while (reader.NextResult());