Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sqlite/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
带自引用外键的Alembic SQLite ALTER表_Sqlite_Foreign Key Relationship_Database Migration_Alembic - Fatal编程技术网

带自引用外键的Alembic SQLite ALTER表

带自引用外键的Alembic SQLite ALTER表,sqlite,foreign-key-relationship,database-migration,alembic,Sqlite,Foreign Key Relationship,Database Migration,Alembic,SQLite数据库的Alembic迁移: def upgrade(): with op.batch_alter_table('my_table') as batch_op: batch_op.add_column(sa.Column('parent_id', sa.String(24))) batch_op.create_foreign_key('parent_constraint', 'my_table', ['parent_id'], ['id'])

SQLite数据库的Alembic迁移:

def upgrade():
    with op.batch_alter_table('my_table') as batch_op:
        batch_op.add_column(sa.Column('parent_id', sa.String(24)))
        batch_op.create_foreign_key('parent_constraint', 'my_table', ['parent_id'], ['id'])
它应该创建一个外键
parent\u id
引用同一个表
my\u table
id
,创建对名为
\u alembic\u batch\u temp
的表的引用:

CREATE TABLE "my_table" (
    id VARCHAR(24) NOT NULL, 
    parent_id VARCHAR(24), 
    PRIMARY KEY (id), 
    CONSTRAINT parent_constraint FOREIGN KEY(parent_id) REFERENCES _alembic_batch_temp (id)
)

如何在更改表时创建自引用约束?

经过一些研究,我发现这里的问题是Alembic执行批迁移的方式。简而言之,在Alembic的当前版本(0.7.6)中,不可能通过迁移创建与self的关系

  • 如Alembic中所述,要进行迁移,将使用临时名称创建新表,并对alter表进行更改 代码。在这种情况下:

    CREATE TABLE _alembic_batch_temp (
        id VARCHAR(24) NOT NULL, 
        parent_id VARCHAR(24), 
        PRIMARY KEY (id), 
        CONSTRAINT parent_constraint FOREIGN KEY(parent_id) REFERENCES _alembic_batch_temp (id)
    )
    
  • 该表由旧表中的数据填充:

    INSERT INTO _alembic_batch_temp (id) SELECT id FROM my_table;
    
    DROP TABLE migration_temp_table;
    
  • 然后删除旧表:

    DROP TABLE my_table;
    
  • 最后,新创建的表将重命名为其正确名称:

    ALTER TABLE _alembic_batch_temp RENAME TO my_table;
    
  • 这种方法的问题在第一个代码段中已经很明显了。新创建的外键正在引用临时表,一旦创建,由于SQLite中的限制,它就无法更改。因此,重命名表后,您将得到您提供的表:

    CREATE TABLE "my_table" (  # new name
        id VARCHAR(24) NOT NULL, 
        parent_id VARCHAR(24), 
        PRIMARY KEY (id), 
        CONSTRAINT parent_constraint FOREIGN KEY(parent_id) REFERENCES _alembic_batch_temp (id)  # old reference
    )
    
    要避免这种情况,可以手动创建批迁移:

  • 将旧表重命名为某个临时名称:

    ALTER TABLE my_table RENAME TO migration_temp_table;
    
  • 创建具有正确名称和正确引用的新表:

    CREATE TABLE my_table (
        id VARCHAR(24) NOT NULL, 
        parent_id VARCHAR(24), 
        PRIMARY KEY (id), 
        CONSTRAINT parent_constraint FOREIGN KEY(parent_id) REFERENCES my_table (id)
    )
    
  • 复制数据:

    INSERT INTO my_table (id) SELECT id FROM migration_temp_table;
    
  • 删除旧表:

    INSERT INTO _alembic_batch_temp (id) SELECT id FROM my_table;
    
    DROP TABLE migration_temp_table;
    

  • 显然,至少在SQLite 3.13.0(.Net 1.0.102.0)中不再需要您的变通方法。我用这个版本测试了这个完全相同的场景(第一个场景),它按照预期工作:使用表重命名自引用。我甚至尝试了一个ON-DELETE级联,我的数据保持在原来的位置:)