20260411091000_RemoveTaskHistoryTaskCodeUniqueHotfix.cs 7.64 KB
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Migrations;
using Rcs.Infrastructure.DB.MsSql;

#nullable disable

namespace Rcs.Infrastructure.Migrations
{
    [DbContext(typeof(AppDbContext))]
    [Migration("20260411091000_RemoveTaskHistoryTaskCodeUniqueHotfix")]
    public class RemoveTaskHistoryTaskCodeUniqueHotfix : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.Sql(
                """
                DO $$
                DECLARE
                    fk_name text;
                    uq_name text;
                    idx_name text;
                BEGIN
                    IF EXISTS (
                        SELECT 1
                        FROM information_schema.tables
                        WHERE table_schema = current_schema()
                          AND table_name = 'robot_sub_task_histories'
                    ) THEN
                        FOR fk_name IN
                            SELECT con.conname
                            FROM pg_constraint con
                            JOIN pg_class rel ON rel.oid = con.conrelid
                            JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
                            JOIN pg_attribute att ON att.attrelid = rel.oid AND att.attnum = ANY(con.conkey)
                            WHERE con.contype = 'f'
                              AND nsp.nspname = current_schema()
                              AND rel.relname = 'robot_sub_task_histories'
                              AND att.attname = 'task_code'
                        LOOP
                            EXECUTE format('ALTER TABLE robot_sub_task_histories DROP CONSTRAINT IF EXISTS %I', fk_name);
                        END LOOP;
                    END IF;

                    IF EXISTS (
                        SELECT 1
                        FROM information_schema.tables
                        WHERE table_schema = current_schema()
                          AND table_name = 'robot_task_histories'
                    ) THEN
                        ALTER TABLE robot_task_histories
                            DROP CONSTRAINT IF EXISTS ak_task_history_task_code;

                        FOR uq_name IN
                            SELECT con.conname
                            FROM pg_constraint con
                            JOIN pg_class rel ON rel.oid = con.conrelid
                            JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
                            JOIN pg_attribute att ON att.attrelid = rel.oid AND att.attnum = ANY(con.conkey)
                            WHERE con.contype = 'u'
                              AND nsp.nspname = current_schema()
                              AND rel.relname = 'robot_task_histories'
                              AND att.attname = 'task_code'
                        LOOP
                            EXECUTE format('ALTER TABLE robot_task_histories DROP CONSTRAINT IF EXISTS %I', uq_name);
                        END LOOP;

                        FOR idx_name IN
                            SELECT i.indexname
                            FROM pg_indexes i
                            WHERE i.schemaname = current_schema()
                              AND i.tablename = 'robot_task_histories'
                              AND i.indexdef ILIKE 'CREATE UNIQUE INDEX%'
                              AND i.indexdef ILIKE '%(task_code)%'
                        LOOP
                            EXECUTE format('DROP INDEX IF EXISTS %I', idx_name);
                        END LOOP;
                    END IF;
                END
                $$;
                """);
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.Sql(
                """
                DO $$
                DECLARE
                    fk_exists boolean;
                BEGIN
                    IF EXISTS (
                        SELECT 1
                        FROM information_schema.tables
                        WHERE table_schema = current_schema()
                          AND table_name = 'robot_task_histories'
                    ) THEN
                        IF NOT EXISTS (
                            SELECT 1
                            FROM pg_constraint con
                            JOIN pg_class rel ON rel.oid = con.conrelid
                            JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
                            WHERE con.contype = 'u'
                              AND nsp.nspname = current_schema()
                              AND rel.relname = 'robot_task_histories'
                              AND con.conname = 'ak_task_history_task_code'
                        ) AND NOT EXISTS (
                            SELECT 1
                            FROM robot_task_histories
                            GROUP BY task_code
                            HAVING COUNT(*) > 1
                        ) THEN
                            ALTER TABLE robot_task_histories
                                ADD CONSTRAINT ak_task_history_task_code UNIQUE (task_code);
                        END IF;
                    END IF;

                    IF EXISTS (
                        SELECT 1
                        FROM information_schema.tables
                        WHERE table_schema = current_schema()
                          AND table_name = 'robot_sub_task_histories'
                    ) AND EXISTS (
                        SELECT 1
                        FROM information_schema.tables
                        WHERE table_schema = current_schema()
                          AND table_name = 'robot_task_histories'
                    ) THEN
                        SELECT EXISTS (
                            SELECT 1
                            FROM pg_constraint con
                            JOIN pg_class rel ON rel.oid = con.conrelid
                            JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
                            WHERE con.contype = 'f'
                              AND nsp.nspname = current_schema()
                              AND rel.relname = 'robot_sub_task_histories'
                              AND con.conname = 'fk_sub_task_history_task_code'
                        ) INTO fk_exists;

                        IF NOT fk_exists
                           AND EXISTS (
                               SELECT 1
                               FROM pg_constraint con
                               JOIN pg_class rel ON rel.oid = con.conrelid
                               JOIN pg_namespace nsp ON nsp.oid = rel.relnamespace
                               WHERE con.contype = 'u'
                                 AND nsp.nspname = current_schema()
                                 AND rel.relname = 'robot_task_histories'
                                 AND con.conname = 'ak_task_history_task_code'
                           )
                           AND NOT EXISTS (
                               SELECT 1
                               FROM robot_sub_task_histories sth
                               LEFT JOIN robot_task_histories th ON th.task_code = sth.task_code
                               WHERE th.task_id IS NULL
                           ) THEN
                            ALTER TABLE robot_sub_task_histories
                                ADD CONSTRAINT fk_sub_task_history_task_code
                                FOREIGN KEY (task_code)
                                REFERENCES robot_task_histories (task_code)
                                ON DELETE CASCADE;
                        END IF;
                    END IF;
                END
                $$;
                """);
        }
    }
}