原生志愿、录取、计划余量、指标资格和通知查询:[CandidateService.Admissions.cs (line 29)](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Infrastructure/Candidate/CandidateService.Admissions.cs:29)
志愿提交、资格校验、补录限制、次数上限与自动锁定:[CandidateService.Admissions.cs (line 152)](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Infrastructure/Candidate/CandidateService.Admissions.cs:152) 通用招生记录读取及事务写入:[CandidateAdmissionRepository.cs (line 25)](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Infrastructure/Candidate/CandidateAdmissionRepository.cs:25) 原生路由已接入:[NativeCandidateEndpoints.cs (line 70)](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Web/Candidate/NativeCandidateEndpoints.cs:70) 迁移状态现在会把 Candidate 标记为原生:[MigrationFeatureCatalog.cs (line 12)](C:/Users/BI/Documents/EIS-dotnet/src/Eis.Infrastructure/Migration/MigrationFeatureCatalog.cs:12)
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
using System.Data.Common;
|
||||
using System.Globalization;
|
||||
using System.Text.Json.Nodes;
|
||||
using Eis.Infrastructure.Data;
|
||||
|
||||
namespace Eis.Infrastructure.Candidate;
|
||||
|
||||
internal sealed record CandidateAdmissionRecord(
|
||||
string Id,
|
||||
string Kind,
|
||||
string ExamId,
|
||||
string? UserId,
|
||||
string? SchoolId,
|
||||
string Status,
|
||||
JsonObject Payload,
|
||||
string CreatedAt,
|
||||
string UpdatedAt);
|
||||
|
||||
internal sealed record CandidateAdmissionSchool(string Id, string Code, string Name);
|
||||
|
||||
internal sealed record CandidateAdmissionSnapshot(
|
||||
IReadOnlyList<CandidateAdmissionRecord> Records,
|
||||
IReadOnlyDictionary<string, CandidateAdmissionSchool> Schools);
|
||||
|
||||
internal sealed class CandidateAdmissionRepository(IRelationalConnectionFactory connectionFactory)
|
||||
{
|
||||
public async Task<CandidateAdmissionSnapshot> LoadAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
await using var connection = await connectionFactory.OpenAsync(cancellationToken);
|
||||
var records = new List<CandidateAdmissionRecord>();
|
||||
await using (var command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = "SELECT id, kind, exam_id, user_id, school_id, status, payload_json, created_at, updated_at FROM admission_records ORDER BY created_at, id";
|
||||
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
|
||||
while (await reader.ReadAsync(cancellationToken))
|
||||
{
|
||||
records.Add(new CandidateAdmissionRecord(
|
||||
ReadString(reader, "id"),
|
||||
ReadString(reader, "kind"),
|
||||
ReadString(reader, "exam_id"),
|
||||
ReadOptionalString(reader, "user_id"),
|
||||
ReadOptionalString(reader, "school_id"),
|
||||
ReadString(reader, "status"),
|
||||
JsonNode.Parse(ReadString(reader, "payload_json"))?.AsObject() ?? new JsonObject(),
|
||||
ReadString(reader, "created_at"),
|
||||
ReadString(reader, "updated_at")));
|
||||
}
|
||||
}
|
||||
|
||||
var schools = new List<CandidateAdmissionSchool>();
|
||||
await using (var command = connection.CreateCommand())
|
||||
{
|
||||
command.CommandText = "SELECT id, code, name FROM schools ORDER BY id";
|
||||
await using var reader = await command.ExecuteReaderAsync(cancellationToken);
|
||||
while (await reader.ReadAsync(cancellationToken))
|
||||
{
|
||||
schools.Add(new CandidateAdmissionSchool(
|
||||
ReadString(reader, "id"),
|
||||
ReadString(reader, "code"),
|
||||
ReadString(reader, "name")));
|
||||
}
|
||||
}
|
||||
|
||||
return new CandidateAdmissionSnapshot(
|
||||
records,
|
||||
schools.ToDictionary(item => item.Id, StringComparer.Ordinal));
|
||||
}
|
||||
|
||||
public async Task SavePreferenceAsync(
|
||||
CandidateAdmissionRecord record,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
await using var connection = await connectionFactory.OpenAsync(cancellationToken);
|
||||
await using var transaction = await connection.BeginTransactionAsync(cancellationToken);
|
||||
try
|
||||
{
|
||||
await using (var delete = connection.CreateCommand())
|
||||
{
|
||||
delete.Transaction = transaction;
|
||||
delete.CommandText = "DELETE FROM admission_records WHERE id = @id";
|
||||
AddParameter(delete, "@id", record.Id);
|
||||
await delete.ExecuteNonQueryAsync(cancellationToken);
|
||||
}
|
||||
|
||||
await using (var insert = connection.CreateCommand())
|
||||
{
|
||||
insert.Transaction = transaction;
|
||||
insert.CommandText = """
|
||||
INSERT INTO admission_records (
|
||||
id, kind, exam_id, user_id, school_id, status, payload_json, created_at, updated_at
|
||||
) VALUES (
|
||||
@id, @kind, @examId, @userId, @schoolId, @status, @payload, @createdAt, @updatedAt
|
||||
)
|
||||
""";
|
||||
AddParameter(insert, "@id", record.Id);
|
||||
AddParameter(insert, "@kind", record.Kind);
|
||||
AddParameter(insert, "@examId", record.ExamId);
|
||||
AddParameter(insert, "@userId", record.UserId);
|
||||
AddParameter(insert, "@schoolId", record.SchoolId);
|
||||
AddParameter(insert, "@status", record.Status);
|
||||
AddParameter(insert, "@payload", record.Payload.ToJsonString());
|
||||
AddParameter(insert, "@createdAt", record.CreatedAt);
|
||||
AddParameter(insert, "@updatedAt", record.UpdatedAt);
|
||||
await insert.ExecuteNonQueryAsync(cancellationToken);
|
||||
}
|
||||
|
||||
await transaction.CommitAsync(cancellationToken);
|
||||
}
|
||||
catch
|
||||
{
|
||||
await transaction.RollbackAsync(cancellationToken);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddParameter(DbCommand command, string name, object? value)
|
||||
{
|
||||
var parameter = command.CreateParameter();
|
||||
parameter.ParameterName = name;
|
||||
parameter.Value = value ?? DBNull.Value;
|
||||
command.Parameters.Add(parameter);
|
||||
}
|
||||
|
||||
private static string ReadString(DbDataReader reader, string name) =>
|
||||
Convert.ToString(reader.GetValue(reader.GetOrdinal(name)), CultureInfo.InvariantCulture) ?? string.Empty;
|
||||
|
||||
private static string? ReadOptionalString(DbDataReader reader, string name)
|
||||
{
|
||||
var ordinal = reader.GetOrdinal(name);
|
||||
return reader.IsDBNull(ordinal) ? null : Convert.ToString(reader.GetValue(ordinal), CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user