试图解决以下问题:
我有三个课程,A
,AB
和B
,因此:
class AB(Base):
id = Column(Integer, primary_key=True)
a_id = Column(Integer, ForeignKey('a.id'), nullable=False)
a = relationship(
'A',
cascade='save-update',
backref=backref(
'abs',
cascade='save-update',
uselist=True
)
)
b_id = Column(Integer, ForeignKey('b.id'), nullable=False)
b = relationship(
'B',
cascade='save-update',
backref=backref(
'abs',
cascade='save-update',
uselist=True
)
)
__tablename__ = 'ab'
class A(Base)
id = Column(Integer, primary_key=True)
__tablename__ = 'a'
class B(Base)
id = Column(Integer, primary_key=True)
__tablename__ = 'b'
基本上,这是A
和B
之间的m2m关系。唯一不标准的是表id
中有一列AB
。这是有原因的。
我想实现A
的两个实例的“合并”。我们获得a1
和a2
。然后,在删除a1
之前,应将其与AB
的所有关系重新分配给a2
。在过程中保留AB.id
的值非常重要(因此,实际上不应创建或删除AB
的新实例)。
问题无论我如何尝试,每次删除A
的实例时,SQLAlchemy都会尝试使用NULL
值更新foreign_key,从而打破{ {1}}约束。它通过发布明确的NOT NULL
来做到这一点。它会这样做,即使我的程序中有以下循环:
UPDATE ab SET a_id = NULL WHERE id = ...
因此,在我发现删除发布之前,与for ab in a1.abs:
ab.a_id = a2.id
session.db.add(ab)
session.db.delete(a1)
相关的所有ab
都已安全地移至a1
,但是出现了问题。
一些非解决方案
a2
标志。行为上的差异只涉及那些不在内存中但不好的行。passive_deletes
级联对我来说非常危险。我想确保在合并过程中没有丢失delete
个对象。ab
)。非常感谢您的帮助!
答案 0 :(得分:1)
每当关系内容与数据库中的实际行集之间存在同步问题时,我建议使用session.expire()
。它会强制在下次访问数据时从数据库重新加载值。
关于过期&刷新:
http://docs.sqlalchemy.org/en/latest/orm/session.html#refreshing-expiring
关于集合中的陈旧数据:
http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#deleting-from-collections
这些功能挽救了我的生命。现在,一切都按预期工作。此外,我可以通过sqlalchemy.sql.expression
API进行批量更新,这通常会快得多,而不会牺牲ORM层中的数据完整性。
答案 1 :(得分:0)
“UPDATE ab SET a_id = NULL WHERE id = a1.id”应该影响0行,因为你已经更新了所有ab,其中ab.a_id = a1.id。
因此只有一种可能的解释,您无法更新ab。电脑往往不撒谎。我们有时只会错过他们的逻辑。
我的解决方案:为了确保每一个都没问题,在发出删除之前,找到所有指向a1.id的ab行,如果它是预期的,你找到至少一个,试着理解为什么那行是还在那里。
也许session.db.add(ab)可以替换为session.db.update(ab)之类的东西,而add()正在向你的ab表添加新行,或者如果不存在更新或者你不能使用它,然后在确保你已经正确制作副本(我认为你有)后首先删除所有ab ab.a_id = a1.id