Symfony Doctrine 迁移破坏了 Postgre 中的主键序列

问题描述 投票:0回答:1

我一直在使用 pg loader 从 MariaDB 迁移到 Postgre

如果我执行

pgloader
来迁移数据库并加载我的程序,一切都会正常;我可以插入一个新的
Post
作为示例

然后我尝试使用

将学说与新数据库同步
docker exec -ti app php bin/console doctrine:migrations:sync-metadata-storage
docker exec -ti app php bin/console make:migration
docker exec -ti app php bin/console doctrine:migrations:migrate 

迁移后如果我尝试插入新的

Post
我会收到错误

SQLSTATE[23505]: Unique violation: 7 ERROR: duplicate key value violates unique constraint "idx_16660_primary"
DETAIL: Key (id)=(1) already exists.

我不确定是什么原因造成的。

查看迁移文件,我可以看到:

        $this->addSql('ALTER TABLE post ALTER id TYPE INT');
        $this->addSql('ALTER TABLE post ALTER id DROP DEFAULT');
        $this->addSql('ALTER TABLE post ALTER id ADD GENERATED BY DEFAULT AS IDENTITY');

如果我从迁移文件中删除最后两行

ALTER id DROP DEFAULT
ALTER id ADD GENERATED BY DEFAULT AS IDENTITY
那么它可以工作,但我的数据库不再同步

这是我的实体的典型 ID

    /**
     * @var int
     */
    #[ORM\Column(name: 'id', type: 'integer', nullable: false)]
    #[Id]
    #[ORM\GeneratedValue(strategy: 'IDENTITY')]
    private $id;
postgresql symfony doctrine
1个回答
0
投票

语句 ALTER TABLE post ALTER id ADD GENERATED BY DEFAULT AS IDENTITY 正在将初始值设置为默认值 1。您显然需要在迁移后重置此值。完成此操作:

ALTER TABLE <table name> 
   ALTER COLUMN <column_name> RESTART WITH <value>;

如果您有多个表或预计需要多次执行此操作,则创建一个过程来执行此操作(请参阅demo了解每个表的示例)。

create or replace procedure post_migration_resync(table_name_in text
                                                 , id_column_in text
                                                 )
 language plpgsql
as $$
declare 
    k_select_max_id constant text = 
        'select max(%I) from %I'; 
       
    k_alter_key_seq constant text =
        'alter table %I alter column %I restart with %s'; 
       
    l_current_max integer;   
    l_statement   text; 
   
begin 
    l_statement = format(k_select_max_id,id_column_in,table_name_in); 
    raise notice '%',E'GET CURRENT MAX:\n ' || l_statement; 
    execute l_statement into l_current_max; 
   
    l_current_max = l_current_max + 10;  -- set for new sequence
    l_statement = format(k_alter_key_seq,table_name_in,id_column_in,l_current_max);
    raise notice '%',E'SET NEW SEQUENCE:\n ' || l_statement; 
    execute l_statement;
   
    commit; 
     
end;
$$;
© www.soinside.com 2019 - 2024. All rights reserved.