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



我有一个包含三个表(A,B和C(的sqlalchemy模式,通过一对多外键关系(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中发生。

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

session_old.expunge(arow)

这将允许您毫无问题地将arow添加到session_new中,但您会注意到没有任何东西插入file_new。这是因为 SQLAlchemy 知道arow是持久的(意味着数据库中有一行与此对象相对应(,当您分离它并将其添加到session_new时,SQLAlchemy 仍然认为它是持久的,因此不会再次插入。

这就是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)

最新更新