sqlite SQLAlchemy:使用外键合并表数据

cngwdvgl  于 2023-03-08  发布在  SQLite
关注(0)|答案(2)|浏览(136)

当我试图更新使用外键作为主键的一部分的行时遇到了问题。下面是一个简化的情况:

class Foo(Base):
    __tablename__ = 'foo_table'
    foo_id = Column(Integer, primary_key=True)
    bar_id = Column(Integer, ForeignKey('bar_table.bar_id'), primary_key=True)
    foo_data = Column(String(255))

    bar = relationship('Bar', backref='foos', foreign_keys=[bar_id])

class Bar(Base):
    __tablename__ = 'bar_table'
    bar_id = Column(Integer, primary_key=True)

首先,我将为foo_table创建一个条目:

f = Foo()
f.foo_id = 1
f.foo_data = 'Foo Data'

现在,我将在bar_table中创建一行,并将两者关联起来:

b = Bar()
f.bar = b

很好!我们将把f添加到会话中并提交:

session.add(f)
session.commit()

现在假设我们遇到了Foo的另一个示例,它具有相同的foo_id,并且与相同的Bar相关,但是具有一些新数据:

f = Foo()
f.foo_id = 1
f.foo_data = 'NEW Foo Data'
f.bar = b

很好!这种情况经常发生,对吧?我将使用session.merge()而不是session.add()更新foo_table中的信息:

session.merge(f)

但这并不好!代码被破解了,我得到了回溯:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 1689, in merge
    self._autoflush()
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 1282, in _autoflush
    self.flush()
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 2004, in flush
    self._flush(objects)
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 2122, in _flush
    transaction.rollback(_capture_exception=True)
  File "/Library/Python/2.7/site-packages/sqlalchemy/util/langhelpers.py", line 60, in __exit__
    compat.reraise(exc_type, exc_value, exc_tb)
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/session.py", line 2086, in _flush
    flush_context.execute()
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 373, in execute
    rec.execute(self)
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/unitofwork.py", line 532, in execute
    uow
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/persistence.py", line 149, in save_obj
    base_mapper, states, uowtransaction
  File "/Library/Python/2.7/site-packages/sqlalchemy/orm/persistence.py", line 301, in _organize_states_for_save
    state_str(existing)))
sqlalchemy.orm.exc.FlushError: New instance <Foo at 0x10a804590> with identity key (<class 'test.Foo'>, (1, 1)) conflicts with persistent instance <Foo at 0x1097a30d0>

有人知道为什么这个更新失败吗?

mi7gmzs6

mi7gmzs61#

我不确定是否有一个真正好的答案......我已经结束了查询,以确定我是否在使用新数据。
所以每当我创建一个新的Foo示例时:

old_foo = session.query(Foo).filter(Foo.id == id).all()
if old_foo:
    foo = old_foo[0]
else:
    foo = Foo()

这看起来并不理想,但我还没有找到另一个有效的解决方案。

l5tcr1uw

l5tcr1uw2#

合并进程中已存在的对象将给予您所看到的错误。
默认情况下,关系启用cascade='save-update, merge'设置:

  • save-update将在调用session.add(object)时向会话添加任何相关对象。
  • merge,在与session.merge(object)合并时将包括任何相关对象。

这在SQLAlchemy关于session.merge()的文档中有更详细的描述。

相关问题