将数据从一个sqlalchemy会话复制到另一个

时间:2017-08-21 17:23:26

标签: python sqlite sqlalchemy

我有一个sqlalchemy架构,包含三个表,(A,B和C)通过一对多外键关系(A-> B之间)和(B-> C)与SQLite相关联后端。我创建了单独的数据库文件来存储数据,每个数据使用完全相同的sqlalchemy模型并运行相同的代码将数据放入其中。

我希望能够从所有这些单独的数据库中复制数据并将它们放入一个新的数据库文件中,同时保留外键关系。我尝试使用以下代码将数据从一个文件复制到新文件:

import sqlalchemy
from sqlalchemy.ext import declarative
from sqlalchemy import Column, String, Integer
from sqlalchemy import orm, engine

Base = declarative.declarative_base()
Session = orm.session_maker()

class A(Base):
    __tablename__ = 'A'

    a_id = Column(Ingeter, primary_key=True)
    adata = Column(String)
    b = orm.relationship('B', back_populates='a', cascade='all, delete-orphan', passive_deletes=True)


class B(Base):
    __tablename__ = 'B'

    b_id = Column(Ingeter, primary_key=True)
    a_id = Column(Integer, sqlalchemy.ForeignKey('A.a_id', ondelete='SET NULL') 
    bdata = Column(String)
    a = orm.relationship('A', back_populates='b')
    c = orm.relationship('C', back_populates='b', cascade='all, delete-orphan', passive_deletes=True)

class C(Base):
    __tablename__ = 'C'

    c_id = Column(Ingeter, primary_key=True)
    b_id = Column(Integer, sqlalchemy.ForeignKey('B.b_id', ondelete='SET NULL') 
    cdata = Column(String)
    b = orm.relationship('B', back_populates='c')


file_new = 'file_new.db'
resource_new = 'sqlite:////%s' % file_new.lstrip('/')
engine_new = sqlalchemy.create_engine(resource_new, echo=False)
session_new = Session(bind=engine_new)

file_old = 'file_old.db'
resource_old = 'sqlite:////%s' % file_old.lstrip('/')
engine_old = sqlalchemy.create_engine(resource_old, echo=False)
session_old = Session(bind=engine_old)

for arow in session_old.query(A):
    session_new.add(arow)  # I am assuming that this will somehow know to copy all the child rows from the tables B and C due to the Foreign Key.

运行时,我收到错误,"对象''已经附加到会话' 2' (这是' 1')"。有关如何使用sqlalchemy和会话执行此操作的任何指示?我还想保留每个数据库中的外键关系。

用例是首先在非联网计算机中本地生成数据并将其聚合到云上的中央数据库中。虽然数据将在SQLite中生成,但合并可能发生在MySQL或Postgres中,尽管为简单起见,所有内容都发生在SQLite中。

1 个答案:

答案 0 :(得分:3)

首先,您收到该错误的原因是arow仍然跟踪实例session_old,因此session_new将拒绝处理它。您可以将其从session_old

分离
session_old.expunge(arow)

这样您就可以毫无问题地将arow添加到session_new,但您会注意到file_new中没有插入任何内容。这是因为SQLAlchemy知道arow是持久的(意味着数据库中对应于此对象的那一行),当你将它分离并添加到session_new时,SQLAlchemy仍然认为它是&# 39;持久性,因此不会再次插入。

这是Session.merge的用武之地。有一点需要注意的是,它不会合并卸载的关系,因此您需要急切加载要合并的所有关系:

query = session_old.query(A).options(orm.subqueryload(A.b),
                                     orm.subqueryload(A.b, B.c))
for arow in query:
    session_new.merge(arow)