196 lines
7.2 KiB
C#
196 lines
7.2 KiB
C#
using System;
|
|
using Microsoft.EntityFrameworkCore.Migrations;
|
|
using NodaTime;
|
|
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
|
|
|
#nullable disable
|
|
|
|
namespace FictionArchive.Service.NovelService.Migrations
|
|
{
|
|
/// <inheritdoc />
|
|
public partial class AddVolumes : Migration
|
|
{
|
|
/// <inheritdoc />
|
|
protected override void Up(MigrationBuilder migrationBuilder)
|
|
{
|
|
// 1. Create the Volume table
|
|
migrationBuilder.CreateTable(
|
|
name: "Volume",
|
|
columns: table => new
|
|
{
|
|
Id = table.Column<long>(type: "bigint", nullable: false)
|
|
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
|
|
Order = table.Column<int>(type: "integer", nullable: false),
|
|
NameId = table.Column<Guid>(type: "uuid", nullable: false),
|
|
NovelId = table.Column<long>(type: "bigint", nullable: false),
|
|
CreatedTime = table.Column<Instant>(type: "timestamp with time zone", nullable: false),
|
|
LastUpdatedTime = table.Column<Instant>(type: "timestamp with time zone", nullable: false)
|
|
},
|
|
constraints: table =>
|
|
{
|
|
table.PrimaryKey("PK_Volume", x => x.Id);
|
|
table.ForeignKey(
|
|
name: "FK_Volume_LocalizationKeys_NameId",
|
|
column: x => x.NameId,
|
|
principalTable: "LocalizationKeys",
|
|
principalColumn: "Id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
table.ForeignKey(
|
|
name: "FK_Volume_Novels_NovelId",
|
|
column: x => x.NovelId,
|
|
principalTable: "Novels",
|
|
principalColumn: "Id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
});
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "IX_Volume_NameId",
|
|
table: "Volume",
|
|
column: "NameId");
|
|
|
|
migrationBuilder.CreateIndex(
|
|
name: "IX_Volume_NovelId_Order",
|
|
table: "Volume",
|
|
columns: new[] { "NovelId", "Order" },
|
|
unique: true);
|
|
|
|
// 2. Add nullable VolumeId column to Chapter (keep NovelId for now)
|
|
migrationBuilder.AddColumn<long>(
|
|
name: "VolumeId",
|
|
table: "Chapter",
|
|
type: "bigint",
|
|
nullable: true);
|
|
|
|
// 3. Data migration: Create volumes and link chapters for each novel
|
|
migrationBuilder.Sql(@"
|
|
DO $$
|
|
DECLARE
|
|
novel_rec RECORD;
|
|
loc_key_id uuid;
|
|
volume_id bigint;
|
|
BEGIN
|
|
FOR novel_rec IN SELECT ""Id"", ""RawLanguage"" FROM ""Novels"" LOOP
|
|
-- Create LocalizationKey for volume name
|
|
loc_key_id := gen_random_uuid();
|
|
INSERT INTO ""LocalizationKeys"" (""Id"", ""CreatedTime"", ""LastUpdatedTime"")
|
|
VALUES (loc_key_id, NOW(), NOW());
|
|
|
|
-- Create LocalizationText for 'Main Story' in novel's raw language
|
|
INSERT INTO ""LocalizationText"" (""Id"", ""LocalizationKeyId"", ""Language"", ""Text"", ""CreatedTime"", ""LastUpdatedTime"")
|
|
VALUES (gen_random_uuid(), loc_key_id, novel_rec.""RawLanguage"", 'Main Story', NOW(), NOW());
|
|
|
|
-- Create Volume for this novel
|
|
INSERT INTO ""Volume"" (""Order"", ""NameId"", ""NovelId"", ""CreatedTime"", ""LastUpdatedTime"")
|
|
VALUES (1, loc_key_id, novel_rec.""Id"", NOW(), NOW())
|
|
RETURNING ""Id"" INTO volume_id;
|
|
|
|
-- Link all chapters of this novel to the new volume
|
|
UPDATE ""Chapter"" SET ""VolumeId"" = volume_id WHERE ""NovelId"" = novel_rec.""Id"";
|
|
END LOOP;
|
|
END $$;
|
|
");
|
|
|
|
// 4. Drop old FK and index for NovelId
|
|
migrationBuilder.DropForeignKey(
|
|
name: "FK_Chapter_Novels_NovelId",
|
|
table: "Chapter");
|
|
|
|
migrationBuilder.DropIndex(
|
|
name: "IX_Chapter_NovelId",
|
|
table: "Chapter");
|
|
|
|
// 5. Drop NovelId column from Chapter
|
|
migrationBuilder.DropColumn(
|
|
name: "NovelId",
|
|
table: "Chapter");
|
|
|
|
// 6. Make VolumeId non-nullable
|
|
migrationBuilder.AlterColumn<long>(
|
|
name: "VolumeId",
|
|
table: "Chapter",
|
|
type: "bigint",
|
|
nullable: false,
|
|
oldClrType: typeof(long),
|
|
oldType: "bigint",
|
|
oldNullable: true);
|
|
|
|
// 7. Add unique index and FK for VolumeId
|
|
migrationBuilder.CreateIndex(
|
|
name: "IX_Chapter_VolumeId_Order",
|
|
table: "Chapter",
|
|
columns: new[] { "VolumeId", "Order" },
|
|
unique: true);
|
|
|
|
migrationBuilder.AddForeignKey(
|
|
name: "FK_Chapter_Volume_VolumeId",
|
|
table: "Chapter",
|
|
column: "VolumeId",
|
|
principalTable: "Volume",
|
|
principalColumn: "Id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
protected override void Down(MigrationBuilder migrationBuilder)
|
|
{
|
|
// Add back NovelId column
|
|
migrationBuilder.AddColumn<long>(
|
|
name: "NovelId",
|
|
table: "Chapter",
|
|
type: "bigint",
|
|
nullable: true);
|
|
|
|
// Migrate data back: set NovelId from Volume
|
|
migrationBuilder.Sql(@"
|
|
UPDATE ""Chapter"" c
|
|
SET ""NovelId"" = v.""NovelId""
|
|
FROM ""Volume"" v
|
|
WHERE c.""VolumeId"" = v.""Id"";
|
|
");
|
|
|
|
// Make NovelId non-nullable
|
|
migrationBuilder.AlterColumn<long>(
|
|
name: "NovelId",
|
|
table: "Chapter",
|
|
type: "bigint",
|
|
nullable: false,
|
|
oldClrType: typeof(long),
|
|
oldType: "bigint",
|
|
oldNullable: true);
|
|
|
|
// Drop VolumeId FK and index
|
|
migrationBuilder.DropForeignKey(
|
|
name: "FK_Chapter_Volume_VolumeId",
|
|
table: "Chapter");
|
|
|
|
migrationBuilder.DropIndex(
|
|
name: "IX_Chapter_VolumeId_Order",
|
|
table: "Chapter");
|
|
|
|
// Drop VolumeId column
|
|
migrationBuilder.DropColumn(
|
|
name: "VolumeId",
|
|
table: "Chapter");
|
|
|
|
// Recreate NovelId index and FK
|
|
migrationBuilder.CreateIndex(
|
|
name: "IX_Chapter_NovelId",
|
|
table: "Chapter",
|
|
column: "NovelId");
|
|
|
|
migrationBuilder.AddForeignKey(
|
|
name: "FK_Chapter_Novels_NovelId",
|
|
table: "Chapter",
|
|
column: "NovelId",
|
|
principalTable: "Novels",
|
|
principalColumn: "Id",
|
|
onDelete: ReferentialAction.Cascade);
|
|
|
|
// Note: Volume LocalizationKeys are not cleaned up in Down migration
|
|
// as they may have been modified. Manual cleanup may be needed.
|
|
migrationBuilder.DropTable(
|
|
name: "Volume");
|
|
}
|
|
}
|
|
}
|